Files
my-os-project2/kernel/intr/intr.c

266 lines
6.0 KiB
C

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#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;
void (*fn)(IntrStackFrame *frame);
int irq;
} IntrHandler;
IntrHandler *INTR_HANDLERS = NULL;
SpinLock INTR_HANDLERS_SPINLOCK;
void intr_attchhandler(void (*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();
}
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) {
if (frame->trapnum == INTR_IRQBASE+0) {
PIT_TICKS++;
intr_pic_eoi(frame->trapnum >= 40);
proc_sched((void *)frame);
} else {
IntrHandler *ih, *ihtmp;
LL_FOREACH_SAFE(INTR_HANDLERS, ih, ihtmp) {
if ((uint64_t)ih->irq == frame->trapnum) {
ih->fn(frame);
}
}
intr_pic_eoi(frame->trapnum >= 40);
}
} else if (frame->trapnum == 0x80) {
intr_syscalldispatch(frame);
}
}