quinn-os/interrupts.c
2022-07-26 20:01:45 +10:00

430 lines
11 KiB
C

#include "inttypes.h"
#include "string.h"
#include "pvec.h"
#include "console.h"
#include "interrupts.h"
#include "schedule.h"
#include "fpu.h"
#include "memory.h"
#include "io.h"
#include "gui.h"
extern void isr0();
extern void isr1();
extern void isr2();
extern void isr3();
extern void isr4();
extern void isr5();
extern void isr6();
extern void isr7();
extern void isr8();
extern void isr9();
extern void isr10();
extern void isr11();
extern void isr12();
extern void isr13();
extern void isr14();
extern void isr15();
extern void isr16();
extern void isr17();
extern void isr18();
extern void isr19();
extern void isr20();
extern void isr21();
extern void isr22();
extern void isr23();
extern void isr24();
extern void isr25();
extern void isr26();
extern void isr27();
extern void isr28();
extern void isr29();
extern void isr30();
extern void isr31();
extern void irq0();
extern void irq1();
extern void irq2();
extern void irq3();
extern void irq4();
extern void irq5();
extern void irq6();
extern void irq7();
extern void irq8();
extern void irq9();
extern void irq10();
extern void irq11();
extern void irq12();
extern void irq13();
extern void irq14();
extern void irq15();
extern void irq16();
struct idt_entry {
uint16_t base_lo;
uint16_t sel;
uint8_t always0;
uint8_t flags;
uint16_t base_hi;
} __attribute__((packed));
extern void abort();
extern struct task_t *current_task;
extern struct tss_t system_tss;
extern void setIdt(struct idt_entry *, unsigned);
struct idt_entry idt[256];
void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) {
idt[num].base_lo = base & 0xffff;
idt[num].sel = sel;
idt[num].always0 = 0;
idt[num].flags = flags;
idt[num].base_hi = base >> 16 & 0xffff;
}
void init_idt() {
memset((char *)idt, 0, sizeof(struct idt_entry) * 256);
setIdt(idt, sizeof(struct idt_entry) * 256);
}
void init_isrs() {
idt_set_gate(0, (uint32_t)isr0, 0x08, 0x8E);
idt_set_gate(1, (uint32_t)isr1, 0x08, 0x8E);
idt_set_gate(2, (uint32_t)isr2, 0x08, 0x8E);
idt_set_gate(3, (uint32_t)isr3, 0x08, 0x8E);
idt_set_gate(4, (uint32_t)isr4, 0x08, 0x8E);
idt_set_gate(5, (uint32_t)isr5, 0x08, 0x8E);
idt_set_gate(6, (uint32_t)isr6, 0x08, 0x8E);
idt_set_gate(7, (uint32_t)isr7, 0x08, 0x8E);
idt_set_gate(8, (uint32_t)isr8, 0x08, 0x8E);
idt_set_gate(9, (uint32_t)isr9, 0x08, 0x8E);
idt_set_gate(10, (uint32_t)isr10, 0x08, 0x8E);
idt_set_gate(11, (uint32_t)isr11, 0x08, 0x8E);
idt_set_gate(12, (uint32_t)isr12, 0x08, 0x8E);
idt_set_gate(13, (uint32_t)isr13, 0x08, 0x8E);
idt_set_gate(14, (uint32_t)isr14, 0x08, 0x8E);
idt_set_gate(15, (uint32_t)isr15, 0x08, 0x8E);
idt_set_gate(16, (uint32_t)isr16, 0x08, 0x8E);
idt_set_gate(17, (uint32_t)isr17, 0x08, 0x8E);
idt_set_gate(18, (uint32_t)isr18, 0x08, 0x8E);
idt_set_gate(19, (uint32_t)isr19, 0x08, 0x8E);
idt_set_gate(20, (uint32_t)isr20, 0x08, 0x8E);
idt_set_gate(21, (uint32_t)isr21, 0x08, 0x8E);
idt_set_gate(22, (uint32_t)isr22, 0x08, 0x8E);
idt_set_gate(23, (uint32_t)isr23, 0x08, 0x8E);
idt_set_gate(24, (uint32_t)isr24, 0x08, 0x8E);
idt_set_gate(25, (uint32_t)isr25, 0x08, 0x8E);
idt_set_gate(26, (uint32_t)isr26, 0x08, 0x8E);
idt_set_gate(27, (uint32_t)isr27, 0x08, 0x8E);
idt_set_gate(28, (uint32_t)isr28, 0x08, 0x8E);
idt_set_gate(29, (uint32_t)isr29, 0x08, 0x8E);
idt_set_gate(30, (uint32_t)isr30, 0x08, 0x8E);
idt_set_gate(31, (uint32_t)isr31, 0x08, 0x8E);
}
extern uint32_t read_cr2();
void print_regs(struct regs *r) {
kprintf("EIP: %p CS: %x\n", r->eip, r->cs);
kprintf("EAX: %p, EBX: %p, ECX: %p, EDX: %p\n", r->eax, r->ebx, r->ecx, r->edx);
kprintf("USER ESP: %p ERROR CODE: %p\n", r->useresp, r->err_code);
kprintf("EDI: %p ESI:%p EBP:%p ESP: %p\n", r->edi, r->esi, r->ebp, r->esp);
kprintf("GS %x, FS %x, ES %x, DS %x\n", r->gs, r->fs, r->es, r->ds);
kprintf("INT NO: %d EFLAGS %x\n", r->int_no, r->eflags);
if (current_task != NULL) {
kprintf("PID: %d CR3 %p USR PAGES AT %p CNT %d\n", current_task->pid, current_task->cr3, current_task->user_pages_at, current_task->user_pages_cnt);
kprintf("KSTACK: 0x%p USTACK: 0x%p TASK: %s\n", current_task->kstack, current_task->ustack, current_task->name);
}
// int i;
/*
struct task_t *task;
int i, j;
for (i=0;i<current_task->user_pages_cnt;i++) {
task = current_task->next_task;
while (task != NULL) {
for (j=0;j<task->user_pages_cnt;j++) {
if (current_task->user_pages[i] == task->user_pages[j]) {
kprintf("MATCH!\n");
}
}
task = task->next_task;
}
}
*/
}
int fault_handler(struct regs *r) {
if (r->int_no == 14) {
// page fault
uint32_t fault_address = read_cr2();
if (fault_address >= 0xd0000000 && fault_address < 0xe0000000) {
if (!mem_map_krnl_page(fault_address & 0xFFFFF000)) {
kprintf("Kernel Page Fault: %p\n", fault_address);
print_regs(r);
gui_flip();
abort();
} else {
return 0;
}
} else if (fault_address >= 0x31000000 && fault_address < 0x32000000) {
kprintf("Kernel Stack Page Fault: %p\n", fault_address);
print_regs(r);
gui_flip();
abort();
} else if (fault_address >= 0x40000000 && fault_address < 0xd0000000) {
if (!mem_map_user_page(fault_address & 0xFFFFF000)) {
kprintf("User Page Fault: %p\n", fault_address);
print_regs(r);
if (r->cs == 0x1b) {
current_task->state = TASK_FINISHED;
schedule(r);
}
gui_flip();
while (1)
;
} else {
return 0;
}
} else {
if (r->cs == 0x1b) {
kprintf("User Page Fault: %p\n", fault_address);
print_regs(r);
current_task->state = TASK_FINISHED;
schedule(r);
}
kprintf("Kernel Page Fault: %p\n", fault_address);
print_regs(r);
gui_flip();
abort();
}
}
if (r->int_no == 6 || r->int_no == 7) {
fpu_isr(r);
return 0;
}
kprintf("Kernel Crash, fault no: %d\n", r->int_no);
while (1)
;
}
// IRQS
// static uint8_t master_mask = 0xFB;
// static uint8_t slave_mask = 0xFF;
struct isr_t {
uint8_t enabled;
uint8_t shared;
uint8_t handlers;
handler_t *handler;
};
static struct isr_t irq_handlers[17];
void irq_clear_mask(uint8_t irq) {
uint16_t port;
uint8_t value;
if (irq < 8) {
port = 0x21;
} else {
port = 0xA1;
irq -= 8;
}
value = inportb(port) & ~(1 << irq);
outportb(port, value);
}
int irq_install_handler(int irq, handler_t handler, uint8_t shared) {
handler_t *tmp;
if (irq_handlers[irq].enabled != 0) {
if (!shared || !irq_handlers[irq].shared) {
return 0;
}
}
if (!irq_handlers[irq].handlers) {
irq_handlers[irq].handler = (handler_t *)dbmalloc(sizeof(handler_t), "irq install handler 1");
if (!irq_handlers[irq].handler) {
return 0;
}
} else {
tmp = (handler_t *)dbrealloc(irq_handlers[irq].handler, sizeof(handler_t) * (irq_handlers[irq].handlers + 1), "irq install handler 2");
if (!tmp) {
return 0;
}
irq_handlers[irq].handler = tmp;
}
irq_handlers[irq].enabled = 1;
irq_handlers[irq].shared = shared;
irq_handlers[irq].handler[irq_handlers[irq].handlers] = handler;
irq_handlers[irq].handlers++;
if (irq > 7) {
irq_clear_mask(2);
}
irq_clear_mask((uint8_t)irq);
return 1;
}
void irq_uninstall_handler(int irq, handler_t handler) {
handler_t *tmp;
int i, j;
for (i = 0; i < irq_handlers[irq].handlers; i++) {
if (irq_handlers[irq].handler[i] == handler) {
for (j = i; j < irq_handlers[irq].handlers - 1; j++) {
irq_handlers[irq].handler[j] = irq_handlers[irq].handler[j + 1];
}
tmp = (handler_t *)dbrealloc(irq_handlers[irq].handler, sizeof(handler_t) * (irq_handlers[irq].handlers - 1), "irq_uninstall handler 1");
if (!tmp) {
abort();
}
irq_handlers[irq].handler = tmp;
break;
}
}
irq_handlers[irq].handlers--;
}
static void io_wait2(void) {
int i;
for (i = 0; i < 5; i++)
;
}
void irq_remap(void) {
uint8_t a1, a2;
a1 = inportb(0x21);
a2 = inportb(0xA1);
outportb(0x20, 0x11);
io_wait2();
outportb(0xA0, 0x11);
io_wait2();
outportb(0x21, 0x20);
io_wait2();
outportb(0xA1, 0x28);
io_wait2();
outportb(0x21, 0x04);
io_wait2();
outportb(0xA1, 0x02);
io_wait2();
outportb(0x21, 0x01);
io_wait2();
outportb(0xA1, 0x01);
io_wait2();
outportb(0x21, a1);
io_wait2();
outportb(0xA1, a2);
io_wait2();
// outportb(0x21, 0xff);
// outportb(0xA1, 0xff);
}
#define PIC1_CMD 0x20
#define PIC1_DATA 0x21
#define PIC2_CMD 0xA0
#define PIC2_DATA 0xA1
#define PIC_READ_IRR 0x0a /* OCW3 irq ready next CMD read */
#define PIC_READ_ISR 0x0b /* OCW3 irq service next CMD read */
/* Helper func */
static uint16_t __pic_get_irq_reg(int ocw3) {
/* OCW3 to PIC CMD to get the register values. PIC2 is chained, and
* represents IRQs 8-15. PIC1 is IRQs 0-7, with 2 being the chain */
outportb(PIC1_CMD, ocw3);
outportb(PIC2_CMD, ocw3);
return (inportb(PIC2_CMD) << 8) | inportb(PIC1_CMD);
}
/* Returns the combined value of the cascaded PICs irq request register */
uint16_t pic_get_irr(void) { return __pic_get_irq_reg(PIC_READ_IRR); }
/* Returns the combined value of the cascaded PICs in-service register */
uint16_t pic_get_isr(void) { return __pic_get_irq_reg(PIC_READ_ISR); }
void init_irqs(void) {
int i;
irq_remap();
idt_set_gate(32, (uint32_t)irq0, 0x08, 0x8E);
idt_set_gate(33, (uint32_t)irq1, 0x08, 0x8E);
idt_set_gate(34, (uint32_t)irq2, 0x08, 0x8E);
idt_set_gate(35, (uint32_t)irq3, 0x08, 0x8E);
idt_set_gate(36, (uint32_t)irq4, 0x08, 0x8E);
idt_set_gate(37, (uint32_t)irq5, 0x08, 0x8E);
idt_set_gate(38, (uint32_t)irq6, 0x08, 0x8E);
idt_set_gate(39, (uint32_t)irq7, 0x08, 0x8E);
idt_set_gate(40, (uint32_t)irq8, 0x08, 0x8E);
idt_set_gate(41, (uint32_t)irq9, 0x08, 0x8E);
idt_set_gate(42, (uint32_t)irq10, 0x08, 0x8E);
idt_set_gate(43, (uint32_t)irq11, 0x08, 0x8E);
idt_set_gate(44, (uint32_t)irq12, 0x08, 0x8E);
idt_set_gate(45, (uint32_t)irq13, 0x08, 0x8E);
idt_set_gate(46, (uint32_t)irq14, 0x08, 0x8E);
idt_set_gate(47, (uint32_t)irq15, 0x08, 0x8E);
idt_set_gate(48, (uint32_t)irq16, 0x08, 0xEE); // syscall
for (i = 0; i < 17; i++) {
irq_handlers[i].enabled = 0;
}
}
int irq_handler(struct regs *r) {
if (current_task != NULL) {
current_task->eflags = r->eflags;
}
// kprintf("intterupt %d\n", r->int_no - 32);
if (r->int_no - 32 == 7) {
// is this a spurious interrupt?
if (!(pic_get_isr() & (1 << 7))) {
// kprintf("Spurious Interrupt 7\n");
return 0;
}
}
if (r->int_no - 32 == 15) {
// is this a spurious interrupt?
if (!(pic_get_isr() & (1 << 15))) {
outportb(0x20, 0x20);
// kprintf("Spurious Interrupt 15\n");
return 0;
}
}
if (irq_handlers[r->int_no - 32].enabled) {
for (int i = 0; i < irq_handlers[r->int_no - 32].handlers; i++) {
handler_t handler;
handler = irq_handlers[r->int_no - 32].handler[i];
if (handler) {
handler(r);
}
}
}
if (r->int_no - 32 >= 8) {
outportb(0xA0, 0x20);
}
outportb(0x20, 0x20);
return 0;
}