diff --git a/bin/boot.bin b/bin/boot.bin
index 9a84534..a0c13b2 100644
Binary files a/bin/boot.bin and b/bin/boot.bin differ
diff --git a/bin/kernel.bin b/bin/kernel.bin
index 746678e..2713f0a 100755
Binary files a/bin/kernel.bin and b/bin/kernel.bin differ
diff --git a/kernel.elf b/kernel.elf
new file mode 100755
index 0000000..4b3024f
Binary files /dev/null and b/kernel.elf differ
diff --git a/obj/kernel/kernel.o b/obj/kernel/kernel.o
index 987d3fc..bb0d8db 100644
Binary files a/obj/kernel/kernel.o and b/obj/kernel/kernel.o differ
diff --git a/obj/kernel/platform/interrupts/int.o b/obj/kernel/platform/interrupts/int.o
index 14dbc95..b117f0f 100644
Binary files a/obj/kernel/platform/interrupts/int.o and b/obj/kernel/platform/interrupts/int.o differ
diff --git a/obj/kernel/platform/interrupts/int_lowlevel.o b/obj/kernel/platform/interrupts/int_lowlevel.o
index 98f9819..c3f6326 100644
Binary files a/obj/kernel/platform/interrupts/int_lowlevel.o and b/obj/kernel/platform/interrupts/int_lowlevel.o differ
diff --git a/os-image.bin b/os-image.bin
index 5d875f0..5a11a77 100644
Binary files a/os-image.bin and b/os-image.bin differ
diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c
index a3f295a..9cac06a 100644
--- a/src/kernel/kernel.c
+++ b/src/kernel/kernel.c
@@ -50,5 +50,5 @@ void main() {
     idt_init();
     kernel_msg_ok("Interrupts initialized");
 
-    __asm__ __volatile__("int $2");
+    //__asm__ __volatile__("int $2");
 }
\ No newline at end of file
diff --git a/src/kernel/platform/interrupts/int.c b/src/kernel/platform/interrupts/int.c
index 3e63985..b1d79a1 100644
--- a/src/kernel/platform/interrupts/int.c
+++ b/src/kernel/platform/interrupts/int.c
@@ -1,8 +1,52 @@
 #include "int.h"
 #include "../../print.h"
 
-void exception_handler() {
-    print_str("I");
+char *exception_messages[] = {
+    "Division By Zero",
+    "Debug",
+    "Non Maskable Interrupt",
+    "Breakpoint",
+    "Into Detected Overflow",
+    "Out of Bounds",
+    "Invalid Opcode",
+    "No Coprocessor",
+
+    "Double Fault",
+    "Coprocessor Segment Overrun",
+    "Bad TSS",
+    "Segment Not Present",
+    "Stack Fault",
+    "General Protection Fault",
+    "Page Fault",
+    "Unknown Interrupt",
+
+    "Coprocessor Fault",
+    "Alignment Check",
+    "Machine Check",
+    "Reserved",
+    "Reserved",
+    "Reserved",
+    "Reserved",
+    "Reserved",
+
+    "Reserved",
+    "Reserved",
+    "Reserved",
+    "Reserved",
+    "Reserved",
+    "Reserved",
+    "Reserved",
+    "Reserved"
+};
+
+void exception_handler(registers_t r) {
+    print_str("int: ");
+    char s[3];
+    int_to_ascii(r.int_no, s);
+    print_str(s);
+    print_str("\n");
+    print_str(exception_messages[r.int_no]);
+    print_str("\n");
 }
 
 void idt_set_descriptor(u8 vector, void* isr, u8 flags) {
diff --git a/src/kernel/platform/interrupts/int.h b/src/kernel/platform/interrupts/int.h
index a58b890..b82f7f5 100644
--- a/src/kernel/platform/interrupts/int.h
+++ b/src/kernel/platform/interrupts/int.h
@@ -21,8 +21,17 @@ typedef struct {
 
 static idtr_t idtr;
 
+typedef struct {
+    u32 ds;                                     // Data segment selector
+    u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha
+    u32 int_no, err_code;                       // Interrupt number and error code (if present)
+    u32 eip, cs, eflags, useresp, ss;           // Pushed automatically by the CPU
+} registers_t;
+
+
+
 __attribute__((noreturn))
-void exception_handler(void);
+void exception_handler(registers_t r);
 
 void idt_set_descriptor(u8 vector, void* isr, u8 flags);
 
diff --git a/src/kernel/platform/interrupts/int_lowlevel.asm b/src/kernel/platform/interrupts/int_lowlevel.asm
index a38fd41..e2a2094 100644
--- a/src/kernel/platform/interrupts/int_lowlevel.asm
+++ b/src/kernel/platform/interrupts/int_lowlevel.asm
@@ -1,13 +1,58 @@
 %macro isr_err_stub 1
 isr_stub_%+%1:
-    call exception_handler
-    iret 
+    push byte %1
+
+    ; Save CPU state
+    pusha          ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
+	mov ax, ds     ; Lower 16-bits of eax = ds.
+	push eax       ; save the data segment descriptor
+	mov ax, 0x10   ; kernel data segment descriptor
+	mov ds, ax
+	mov es, ax
+	mov fs, ax
+	mov gs, ax
+
+    call exception_handler ; Call C handler
+
+    ; Restore CPU state
+    pop eax 
+	mov ds, ax
+	mov es, ax
+	mov fs, ax
+	mov gs, ax
+	popa
+	add esp, 8 ; Cleans up the pushed error code and pushed ISR number
+	sti
+	iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
 %endmacro
 ; if writing for 64-bit, use iretq instead
 %macro isr_no_err_stub 1
 isr_stub_%+%1:
-    call exception_handler
-    iret
+    push byte 0
+    push byte %1
+
+    ; Save CPU state
+    pusha          ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
+	mov ax, ds     ; Lower 16-bits of eax = ds.
+	push eax       ; save the data segment descriptor
+	mov ax, 0x10   ; kernel data segment descriptor
+	mov ds, ax
+	mov es, ax
+	mov fs, ax
+	mov gs, ax
+
+    call exception_handler ; Call C handler
+
+    ; Restore CPU state
+    pop eax 
+	mov ds, ax
+	mov es, ax
+	mov fs, ax
+	mov gs, ax
+	popa
+	add esp, 8 ; Cleans up the pushed error code and pushed ISR number
+	sti
+	iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
 %endmacro
 
 extern exception_handler