Begin task refactor

Store state using interrupt stack instead. Looks like `int 0x80` doesn't
work though, which is odd.
diff --git a/.gitignore b/.gitignore
index 2856816..6661bef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,5 @@
 **/Jmk.options
 .gitignore
 .idea
-.vscode
 **/.#*
 src/kernel/dri/pci/vendors.c
\ No newline at end of file
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
new file mode 100644
index 0000000..1552d82
--- /dev/null
+++ b/.vscode/c_cpp_properties.json
@@ -0,0 +1,23 @@
+{
+    "configurations": [
+        {
+            "name": "Bluejay",
+            "includePath": [
+                "${workspaceFolder}/**",
+                "${workspaceFolder}/include",
+                "${workspaceFolder}/include/kernel",
+                "${workspaceFolder}/src/kernel"
+            ],
+            "defines": [],
+            "compilerPath": "/usr/bin/gcc",
+            "cStandard": "c11",
+            // "cppStandard": "c++14",
+            "intelliSenseMode": "linux-gcc-x86",
+            // "compileCommands": "${workspaceFolder}/compile_commands.json",
+            "compilerArgs": [
+                "-nostdinc -nostdlib -O2 -m32 -g"
+            ]
+        }
+    ],
+    "version": 4
+}
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..57b1c71
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,18 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "type": "gdb",
+            "request": "attach",
+            "name": "Attach to QEMU",
+            "executable": "./src/kernel/kernel.elf",
+            "target": ":1234",
+            "remote": true,
+            "cwd": "${workspaceRoot}",
+            "valuesFormatting": "parseText",
+        }
+    ]
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..3ca0ef0
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,17 @@
+{
+    // See https://go.microsoft.com/fwlink/?LinkId=733558
+    // for the documentation about the tasks.json format
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "qemu:build",
+            "type": "shell",
+            "command": "make -C src/kernel/ debug-wait",
+            "problemMatcher": [],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
+        }
+    ],
+}
\ No newline at end of file
diff --git a/src/kernel/Jmk b/src/kernel/Jmk
index 8300fd8..0ae3053 100644
--- a/src/kernel/Jmk
+++ b/src/kernel/Jmk
@@ -44,6 +44,7 @@
 			syscall.o \
 			task.o \
 			task_api.o \
+			faults.o \
 			lib(ata_pio) \
 			lib(pci)
 
diff --git a/src/kernel/descriptor_tables.c b/src/kernel/descriptor_tables.c
index 916a1ae..94f62df 100644
--- a/src/kernel/descriptor_tables.c
+++ b/src/kernel/descriptor_tables.c
@@ -3,6 +3,7 @@
 #include "log.h"
 #include "pic.h"
 #include "vga.h"
+#include "faults.h"
 
 extern void gdt_flush(uint gdt);
 extern void idt_flush(uint idt);
@@ -74,6 +75,8 @@
 	// Remap PIC
 	pic_remap();
 
+	init_faults();
+
 	vga_set_color(CYAN, BLACK);
 	for (int i = 0; i < 16; i++)
 	{
@@ -107,5 +110,4 @@
 {
 	init_gdt();
 	init_idt();
-	memset(interrupt_handlers, 0, sizeof(interrupt_handlers));
 }
diff --git a/src/kernel/faults.c b/src/kernel/faults.c
new file mode 100644
index 0000000..ba5a615
--- /dev/null
+++ b/src/kernel/faults.c
@@ -0,0 +1,22 @@
+#include "pic.h"
+#include <log.h>
+
+#define DECLARE_INTERRUPT(sym, name)                                           \
+	static void sym##_h(struct registers *regs)                                \
+	{                                                                          \
+		kprintf("Fault " name ": eip = 0x%x, err = 0x%x\n", regs->eip,         \
+				regs->error_code);                                             \
+		asm volatile("cli");                                                   \
+		kpanic(name);                                                          \
+	}
+
+#define ADD_INTERRUPT(sym, num) add_interrupt_handler(num, sym##_h)
+
+DECLARE_INTERRUPT(gp, "#GP")
+DECLARE_INTERRUPT(pf, "#PF")
+
+void init_faults()
+{
+	ADD_INTERRUPT(gp, 13);
+	ADD_INTERRUPT(pf, 14);
+}
diff --git a/src/kernel/faults.h b/src/kernel/faults.h
new file mode 100644
index 0000000..a85b4ec
--- /dev/null
+++ b/src/kernel/faults.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void init_faults();
\ No newline at end of file
diff --git a/src/kernel/main.c b/src/kernel/main.c
index 55c562a..876c647 100644
--- a/src/kernel/main.c
+++ b/src/kernel/main.c
@@ -74,6 +74,8 @@
 	}
 #endif
 
+	asm volatile("sti");
+
 	kprintf("initializing tasks\n");
 	init_tasks();
 	kprintf("\ndone initializing tasks\n");
@@ -88,6 +90,7 @@
 	test_ata_pio();
 #endif
 
+#ifdef TEST_PCI
 	kprintf("Enumerating PCI devices:\n");
 	for (int bus = 0; bus < 0xff; bus++)
 	{
@@ -106,7 +109,8 @@
 			}
 		}
 	}
-	
+#endif
+
 	while (true)
 		asm volatile("hlt");
 
diff --git a/src/kernel/pic.c b/src/kernel/pic.c
index 1c96543..a9a06ef 100644
--- a/src/kernel/pic.c
+++ b/src/kernel/pic.c
@@ -14,7 +14,9 @@
 #define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
 #define ICW4_SFNM 0x10		 /* Special fully nested (not) */
 
-void (*interrupt_handlers[256])(struct registers *);
+typedef void (*interrupt_handler_t)(struct registers *);
+
+static interrupt_handler_t interrupt_handlers[256];
 
 void pic_send_eoi(uchar interrupt)
 {
@@ -60,5 +62,5 @@
 	outb(0x21, 0x0);
 	outb(0xA1, 0x0);
 
-	return;
+	memset(interrupt_handlers, 0, sizeof(interrupt_handlers));
 }
diff --git a/src/kernel/task.c b/src/kernel/task.c
index 4d740cf..53a31e6 100644
--- a/src/kernel/task.c
+++ b/src/kernel/task.c
@@ -3,14 +3,31 @@
 #include "io.h"
 #include "log.h"
 #include "paging.h"
+#include "pic.h"
 
 struct process processes[1024] = {0};
 struct ll_task_i *first_task = NULL, *last_task = NULL, *current_task = NULL;
 static uint next_task_id = 0;
 
+bool tasks_initialized = false;
+
+void _init_tasks(uint kernel_esp, uint kernel_ebp, uint kernel_eip);
+
+void init_tasks()
+{
+	add_interrupt_handler(INIT_TASKS_INTERRUPT, _sys_init_tasks_h);
+
+	asm("int $0x80");
+}
+
+void _sys_init_tasks_h(struct registers *regs)
+{
+	_init_tasks(regs->esp, regs->ebp, regs->eip);
+}
+
 void _init_tasks(uint kernel_esp, uint kernel_ebp, uint kernel_eip)
 {
-	kprintf("_init_tasks\n");
+	kpanic("_init_tasks\n");
 
 	processes[0] = (struct process){
 		.exists = true,
@@ -42,6 +59,8 @@
 	};
 
 	kprintf("Returning from _init_tasks\n");
+
+	tasks_initialized = true;
 }
 
 struct process *get_process(uint pid)
diff --git a/src/kernel/task.h b/src/kernel/task.h
index ce5b04c..487c143 100644
--- a/src/kernel/task.h
+++ b/src/kernel/task.h
@@ -3,6 +3,10 @@
 #include "kint.h"
 #include "registers.h"
 
+#define INIT_TASKS_INTERRUPT 0x81
+
+extern bool tasks_initialized;
+
 struct process
 {
 	bool exists;
@@ -34,7 +38,8 @@
 // extern struct process processes[1024];
 // extern struct ll_task_i *first_task, *current_task;
 
-extern void init_tasks();
+// Note: interrupts must be enabled BEFORE this for it to work.
+void init_tasks();
 struct process *get_process(uint pid);
 
 int get_process_id();
@@ -47,3 +52,4 @@
 void kill_this_thread();
 extern void switch_task();
 void switch_to_task(struct task *task);
+void _sys_init_tasks_h(struct registers *regs);
diff --git a/src/kernel/task_api.s b/src/kernel/task_api.s
index 1673866..01f3ca4 100644
--- a/src/kernel/task_api.s
+++ b/src/kernel/task_api.s
@@ -30,15 +30,3 @@
 	mov cr3, ecx 				; Set page directory
 	sti
 	jmp eax 					; Jump back to code
-
-	[extern _init_tasks]
-	[global init_tasks]
-init_tasks:
-	lea eax, [esp + 4] 			; Stack pointer before call
-	mov ebx, [esp] 				; Return address
-	push ebx					; eip
-	push ebp					; ebp
-	push eax 					; esp
-	call _init_tasks
-	add esp, 12
-	ret
diff --git a/src/kernel/timer.c b/src/kernel/timer.c
index 8ed0be8..be177f9 100644
--- a/src/kernel/timer.c
+++ b/src/kernel/timer.c
@@ -9,8 +9,11 @@
 
 static void timer_cb(struct registers *regs)
 {
-	// Preemptive multitasking!
-	switch_task();
+	if (tasks_initialized)
+	{
+		// Preemptive multitasking!
+		switch_task();
+	}
 }
 
 void init_timer(uint hz)