#include #include #include #include "intr/intr.h" #include "intr/pic.h" #include "intr/pit.h" #include "io/io.h" #include "cpu/gdt.h" #include "compiler/attr.h" #include "proc/proc.h" #include "syscall/syscall.h" #include "ipc/pipe/pipe.h" #include "rbuf/rbuf.h" #include "dlmalloc/malloc.h" #include "util/util.h" #include "cpu/hang.h" #include "kprintf.h" #include "errors.h" typedef struct IntrHandler { struct IntrHandler *next; int (*fn)(IntrStackFrame *frame); int irq; } IntrHandler; IntrHandler *INTR_HANDLERS = NULL; SpinLock INTR_HANDLERS_SPINLOCK; void intr_attchhandler(int (*fn)(IntrStackFrame *frame), int irq) { IntrHandler *ih = dlmalloc(sizeof(*ih)); ih->fn = fn; ih->irq = irq; spinlock_acquire(&INTR_HANDLERS_SPINLOCK); LL_APPEND(INTR_HANDLERS, ih); spinlock_release(&INTR_HANDLERS_SPINLOCK); } int32_t intr_dttchhandler(int irq) { IntrHandler *ih = NULL; spinlock_acquire(&INTR_HANDLERS_SPINLOCK); LL_FINDPROP(INTR_HANDLERS, ih, irq, irq); if (ih == NULL) { spinlock_release(&INTR_HANDLERS_SPINLOCK); return E_NOENTRY; } LL_REMOVE(INTR_HANDLERS, ih); spinlock_release(&INTR_HANDLERS_SPINLOCK); dlfree(ih); return E_OK; } typedef struct BackTraceFrame { struct BackTraceFrame *rbp; uint64_t rip; } BackTraceFrame; void intr_backtrace(BackTraceFrame *bt) { kprintf("Backtrace:\n"); for (size_t frame = 0; bt; frame++) { kprintf(" %zu: 0x%lx\n", frame, bt->rip); bt = bt->rbp; } } void intr_disable(void) { asm volatile("cli"); } void intr_enable(void) { asm volatile("sti"); } typedef struct { uint16_t intrlow; uint16_t kernelcs; uint8_t ist; uint8_t attrs; uint16_t intrmid; uint32_t intrhigh; uint32_t resv; } PACKED IdtGate; typedef struct { uint16_t limit; uint64_t base; } PACKED Idt; #define ENTRIES 256 ALIGNED(0x10) static IdtGate idtgates[ENTRIES] = {0}; static Idt idt = {0}; void idt_setentry(int i, uint64_t handler, uint8_t flags) { idtgates[i].intrlow = handler & 0xffff; idtgates[i].kernelcs = KCODE; idtgates[i].ist = 0; idtgates[i].attrs = flags; idtgates[i].intrmid = (handler >> 16) & 0xFFFF; idtgates[i].intrhigh = (handler >> 32) & 0xFFFFFFFF; idtgates[i].resv = 0; } void idt_init(void) { idt.base = (uint64_t)&idtgates; idt.limit = ENTRIES * sizeof(IdtGate) - 1; asm volatile("lidt %0" :: "m"(idt) : "memory"); LOG("hal", "idt init\n"); } extern void *ISR_REDIRTABLE[]; static const char *exceptions[] = { "#DE", "#DB", "NMI", "#BP", "#OF", "#BR", "#UD", "#NM", "#DF", "CSO", "#TS", "#NP", "#SS", "#GP", "#PF", "RES", "#MF", "#AC", "#MC", "#XM", "#VE", "#CP", }; void intr_init(void) { spinlock_init(&INTR_HANDLERS_SPINLOCK); #define MKINTR(N) \ extern void intr_vec##N(void); \ idt_setentry(N, (uint64_t)&intr_vec##N, 0x8E); MKINTR(0); MKINTR(1); MKINTR(2); MKINTR(4); MKINTR(5); MKINTR(6); MKINTR(7); MKINTR(8); MKINTR(9); MKINTR(10); MKINTR(11); MKINTR(12); MKINTR(13); MKINTR(14); MKINTR(15); MKINTR(16); MKINTR(17); MKINTR(18); MKINTR(19); MKINTR(20); MKINTR(21); MKINTR(22); MKINTR(23); MKINTR(24); MKINTR(25); MKINTR(26); MKINTR(27); MKINTR(28); MKINTR(29); MKINTR(30); MKINTR(31); MKINTR(32); MKINTR(33); MKINTR(34); MKINTR(35); MKINTR(36); MKINTR(37); MKINTR(38); MKINTR(39); MKINTR(40); MKINTR(41); MKINTR(42); MKINTR(43); MKINTR(44); MKINTR(45); MKINTR(46); MKINTR(47); extern void intr_vec128(void); idt_setentry(0x80, (uint64_t)&intr_vec128, 0xEE); idt_init(); intr_pic_init(); intr_pit_init(); intr_disable(); } void intr_dumpframe(IntrStackFrame *frame) { uint64_t cr2; asm volatile("mov %%cr2, %0" : "=r"(cr2)); uint64_t cr3; asm volatile("mov %%cr3, %0" : "=r"(cr3)); uint64_t cr4; asm volatile("mov %%cr4, %0" : "=r"(cr4)); kprintf("rax=%016lx rcx=%016lx rdx=%016lx\n" "rsi=%016lx rdi=%016lx r8 =%016lx\n" "r9 =%016lx r10=%016lx r11=%016lx\n" "rip=%016lx rfl=%016lx rsp=%016lx\n" "cs =%016lx ss =%016lx trp=%016lx\n" "cr2=%016lx cr3=%016lx cr4=%016lx\n" "\n\n", frame->regs.rax, frame->regs.rcx, frame->regs.rdx, frame->regs.rsi, frame->regs.rdi, frame->regs.r8, frame->regs.r9, frame->regs.r10, frame->regs.r11, frame->rip, frame->rflags, frame->rsp, frame->cs, frame->ss, frame->trapnum, cr2, cr3, cr4 ); } void intr_syscalldispatch(IntrStackFrame *frame) { uint64_t sysnum = frame->regs.rax; if (sysnum < SYSCALLS_MAX) { SyscallFn fn = SYSCALL_TABLE[sysnum]; if (fn == NULL) { frame->regs.rax = E_BADSYSCALL; return; } uint64_t calling_proc_pid = PROCS.current->pid; intr_enable(); int32_t ret = fn(frame, calling_proc_pid, frame->regs.rdi, frame->regs.rsi, frame->regs.rdx, frame->regs.r10, frame->regs.r8, frame->regs.r9); if (ret == E_DOSCHEDULING) { proc_sched((void *)frame); } frame->regs.rax = *(uint64_t *)&ret; } } void intr_handleintr(IntrStackFrame *frame) { if (frame->trapnum <= 31) { kprintf("ERROR %s, 0x%lX\n", exceptions[frame->trapnum], frame->errnum); intr_dumpframe(frame); intr_backtrace((BackTraceFrame *)frame->regs.rbp); if (frame->cs == (UCODE | 0x3)) { kprintf("killed pid %ld %s\n", PROCS.current->pid, PROCS.current->name); proc_killself(); proc_sched((void *)frame); } else { kprintf("Kernel error :(\n"); cpu_hang(); } } else if (frame->trapnum >= 32 && frame->trapnum <= 47) { bool send = true; IntrHandler *ih, *ihtmp; LL_FOREACH_SAFE(INTR_HANDLERS, ih, ihtmp) { if ((uint64_t)ih->irq == frame->trapnum) { if (ih->fn(frame) == INTR_NOEOI) { send = false; } } } if (send) intr_pic_eoi(); } else if (frame->trapnum == 0x80) { intr_syscalldispatch(frame); } }