diff --git a/Makefile b/Makefile
index 6cd758c..3e8a13a 100644
--- a/Makefile
+++ b/Makefile
@@ -37,11 +37,11 @@ obj/%.o: src/%.asm
 
 
 run: clean bin/shade.iso
-	qemu-system-x86_64 -hdd bin/shade.iso
+	qemu-system-x86_64 -hdd bin/shade.iso -d int -no-reboot
 
 debug: clean bin/shade.iso bin/shade.bin
-	qemu-system-x86_64 -s -S -hdd bin/shade.iso &
-	${GDB} os-image.bin -ex "symbol-file bin/shade.bin" -ex "target remote localhost:1234"
+	qemu-system-x86_64 -s -S -hdd bin/shade.iso -d int -no-reboot &
+	${GDB} os-image.bin -ex "set arch i386:x86-64" -ex "symbol-file bin/shade.bin" -ex "target remote localhost:1234"
 
 
 clean:
diff --git a/bin/shade.bin b/bin/shade.bin
index b755599..bc273eb 100755
Binary files a/bin/shade.bin and b/bin/shade.bin differ
diff --git a/bin/shade.iso b/bin/shade.iso
index 080a0ab..f81d3d4 100644
Binary files a/bin/shade.iso and b/bin/shade.iso differ
diff --git a/bin/shade.iso.lock b/bin/shade.iso.lock
new file mode 100644
index 0000000..e69de29
diff --git a/bochsrc.txt b/bochsrc.txt
new file mode 100644
index 0000000..2ba3db3
--- /dev/null
+++ b/bochsrc.txt
@@ -0,0 +1,57 @@
+# configuration file generated by Bochs
+plugin_ctrl: unmapped=true, biosdev=true, speaker=true, extfpuirq=true, parallel=true, serial=true, iodebug=true, pcidev=false, usb_uhci=false
+config_interface: textconfig
+display_library: x
+memory: host=32, guest=32
+romimage: file="/usr/share/bochs/BIOS-bochs-latest", address=0x00000000, options=none
+vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest"
+boot: floppy
+floppy_bootsig_check: disabled=0
+floppya: type=1_44
+# no floppyb
+ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
+ata0-master: type=disk, path="bin/shade.iso", mode=flat, cylinders=0, heads=0, spt=0, sect_size=512, model="Generic 1234", biosdetect=auto, translation=auto
+ata0-slave: type=none
+ata1: enabled=true, ioaddr1=0x170, ioaddr2=0x370, irq=15
+ata1-master: type=none
+ata1-slave: type=none
+ata2: enabled=false
+ata3: enabled=false
+optromimage1: file=none
+optromimage2: file=none
+optromimage3: file=none
+optromimage4: file=none
+optramimage1: file=none
+optramimage2: file=none
+optramimage3: file=none
+optramimage4: file=none
+pci: enabled=1, chipset=i440fx, slot1=none, slot2=none, slot3=none, slot4=none, slot5=none
+vga: extension=vbe, update_freq=5, realtime=1, ddc=builtin
+cpu: count=1:1:1, ips=4000000, quantum=16, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
+cpuid: level=6, stepping=3, model=3, family=6, vendor_string="AuthenticAMD", brand_string="AMD Athlon(tm) processor"
+cpuid: mmx=true, apic=xapic, simd=sse2, sse4a=false, misaligned_sse=false, sep=true
+cpuid: movbe=false, adx=false, aes=false, sha=false, xsave=false, xsaveopt=false, avx_f16c=false
+cpuid: avx_fma=false, bmi=0, xop=false, fma4=false, tbm=false, x86_64=true, 1g_pages=false
+cpuid: pcid=false, fsgsbase=false, smep=false, smap=false, mwait=true
+print_timestamps: enabled=0
+debugger_log: -
+magic_break: enabled=0
+port_e9_hack: enabled=0
+private_colormap: enabled=0
+clock: sync=none, time0=local, rtc_sync=0
+# no cmosimage
+log: -
+logprefix: %t%e%d
+debug: action=ignore
+info: action=report
+error: action=report
+panic: action=ask
+keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none
+mouse: type=ps2, enabled=false, toggle=ctrl+mbutton
+speaker: enabled=true, mode=system
+parport1: enabled=true, file=none
+parport2: enabled=false
+com1: enabled=true, mode=null
+com2: enabled=false
+com3: enabled=false
+com4: enabled=false
diff --git a/obj/boot.o b/obj/boot.o
index 8b05e99..b5ff9cd 100644
Binary files a/obj/boot.o and b/obj/boot.o differ
diff --git a/obj/kernel/kernel.o b/obj/kernel/kernel.o
index 0c6d63b..4c95461 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
new file mode 100644
index 0000000..0a99241
Binary files /dev/null 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
new file mode 100644
index 0000000..98f9819
Binary files /dev/null and b/obj/kernel/platform/interrupts/int_lowlevel.o differ
diff --git a/old/src/boot/protected/gdt.asm b/old/src/boot/protected/gdt.asm
index db35b41..df7bfe2 100644
--- a/old/src/boot/protected/gdt.asm
+++ b/old/src/boot/protected/gdt.asm
@@ -1,3 +1,4 @@
+
 gdt_start: ; use labels to compute sizes and jumps
     ; gdt starts with 8 byte null
     dd 0x0
diff --git a/old/src/kernel/platform/gdt.h b/old/src/kernel/platform/gdt.h
new file mode 100644
index 0000000..5545747
--- /dev/null
+++ b/old/src/kernel/platform/gdt.h
@@ -0,0 +1,28 @@
+#ifndef GDT_H
+#define GDT_H
+
+#include <stdint.h>
+
+// the GDT descriptor format makes literally no sense, who came up with this
+typedef struct {
+    uint16_t limit_low16; // Low 16 bits of limit
+    uint16_t base_low16;  // Low 16 bits of base
+    uint8_t  base_mid8;   // Middle 8 bits of base
+    uint8_t  access;      // 7: present, 6-5: priv level, 4: type, 3: executable, 2: dc, 1: rw, 0: accessed (zero)
+    uint8_t  limit_flags; // High 4 bits of limit AND flags (?? why). flags: 3: granularity, 2: size, 1: long, 0: reserved
+    uint8_t  base_high8;  // High 8 bits of base
+} __attribute__((packed)) gdt_entry_t;
+
+typedef struct {
+    uint16_t size;   // GDT size (bytes) - 1
+    uint32_t offset; // Address of element 0 of the GDT
+} __attribute__((packed)) gdt_ptr_t;
+
+static gdt_entry_t gdt[8192];
+static gdt_ptr_t gdtr;
+
+void init_gdt();
+void gdt_set_segment(int limit, int base, int access);
+void load_gdt();
+
+#endif
\ No newline at end of file
diff --git a/src/boot.asm b/src/boot.asm
index a265974..c4eac95 100644
--- a/src/boot.asm
+++ b/src/boot.asm
@@ -18,6 +18,8 @@ stack_bottom:
 resb 16384
 stack_top:
 
+%include "src/gdt.asm"
+
 ; _start = entry to kernel
 ; Since the bootloader will be gone, it doesn't make sense to return from this
 section .text
@@ -27,6 +29,18 @@ _start:
     ; 32bit protected mode, no int, no paging
     mov esp, stack_top ; Initialize stack
 
+    cli ; Disable interrupts
+    lgdt [gdt_descriptor] ; load the GDT
+    jmp CODE_SEG:.reload_seg ; far jump into a different segment
+
+.reload_seg: ; now in 32bit
+    mov ax, DATA_SEG ; update segment registers
+    mov ds, ax
+    mov ss, ax
+    mov es, ax
+    mov fs, ax
+    mov gs, ax
+
     extern kmain
     call kmain
 
diff --git a/src/gdt.asm b/src/gdt.asm
new file mode 100644
index 0000000..94a1299
--- /dev/null
+++ b/src/gdt.asm
@@ -0,0 +1,33 @@
+section .data
+
+gdt_start: ; use labels to compute sizes and jumps
+    ; gdt starts with 8 byte null
+    dd 0x0
+    dd 0x0
+
+; GDT for code segment, base = 0x00000000, length = 0xfffff
+gdt_code:
+    dw 0xffff ; segment length
+    dw 0x0 ; segment base
+    db 0x0 ; segment base
+    db 10011010b ; flags
+    db 11001111b ; flags + segment length
+    db 0x0 ; segment base
+
+; GDT for data segment
+gdt_data:
+    dw 0xffff ; segment length
+    dw 0x0 ; segment base
+    db 0x0 ; segment base
+    db 10010010b ; flags
+    db 11001111b ; flags + segment length
+    db 0x0 ; segment base
+
+gdt_end:
+
+gdt_descriptor:
+    dw gdt_end - gdt_start - 1 ; size, always 1 less than what it actually is
+    dd gdt_start ; address
+
+CODE_SEG equ gdt_code - gdt_start
+DATA_SEG equ gdt_data - gdt_start
\ No newline at end of file
diff --git a/src/iso/grub.cfg b/src/iso/grub.cfg
index d6d553e..1fdb214 100644
--- a/src/iso/grub.cfg
+++ b/src/iso/grub.cfg
@@ -1,3 +1,6 @@
+set timeout=0
+set default=0
+
 menuentry "shadeOS Dev Build" {
     multiboot /boot/shade.bin
 }
\ No newline at end of file
diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c
index 33df331..3002fb1 100644
--- a/src/kernel/kernel.c
+++ b/src/kernel/kernel.c
@@ -1,7 +1,6 @@
 #include "./platform/drivers/ports.h"
 #include "print.h"
-#include "./platform/types.h"
-//#include "./platform/interrupts/int.h"
+#include "./platform/interrupts/int.h"
 
 void dummy_test_entrypoint() {}
 
@@ -46,10 +45,10 @@ void kmain() {
     print_str("Copyright (c) e3team 2022. All rights reserved.\n");
     print_str("This program is provided \"as-is\" and no express or implied warranty is provided.\n");
     print_str("The full license can be found at /sys/LICENCE on this system or ./LICENCE in the source tree.\n");
-/*
+
     idt_init();
-    kernel_msg_ok("Interrupts initialized");
 
     __asm__ __volatile__("int $2");
-*/
+
+    //kernel_msg_ok("Interrupts working");
 }
\ No newline at end of file
diff --git a/src/kernel/platform/interrupts/int.c b/src/kernel/platform/interrupts/int.c
new file mode 100644
index 0000000..7474267
--- /dev/null
+++ b/src/kernel/platform/interrupts/int.c
@@ -0,0 +1,35 @@
+#include "int.h"
+#include "../../print.h"
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+int count = 0;
+
+void exception_handler() {
+    print_str("I");
+}
+
+void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags) {
+    idt_entry_t* descriptor = &idt[vector];
+ 
+    descriptor->isr_low        = (uint32_t)isr & 0xFFFF;
+    descriptor->kernel_cs      = 0x08; // this value can be whatever offset your kernel code selector is in your GDT
+    descriptor->attributes     = flags;
+    descriptor->isr_high       = (uint32_t)isr >> 16;
+    descriptor->reserved       = 0;
+}
+
+void idt_init() {
+    idtr.base = (uint32_t)&idt[0];
+    idtr.limit = (uint16_t)sizeof(idt_entry_t) * 256 - 1;
+ 
+    for (uint8_t vector = 0; vector < 32; vector++) {
+        idt_set_descriptor(vector, isr_stub_table[vector], 0x8E);
+        isr_stub_table[vector] = true;
+    }
+ 
+    __asm__ volatile ("lidt %0" : : "m"(idtr)); // load the new IDT
+    __asm__ volatile ("sti"); // set the interrupt flag
+}
\ No newline at end of file
diff --git a/src/kernel/platform/interrupts/int.h b/src/kernel/platform/interrupts/int.h
new file mode 100644
index 0000000..f2a0d01
--- /dev/null
+++ b/src/kernel/platform/interrupts/int.h
@@ -0,0 +1,43 @@
+#ifndef INT_H
+#define INT_H
+
+#include "../../util.h"
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+	uint16_t isr_low;      // The lower 16 bits of the ISR's address
+	uint16_t kernel_cs;    // The GDT segment selector that the CPU will load into CS before calling the ISR
+	uint8_t  reserved;     // Set to zero
+	uint8_t  attributes;   // Type and attributes; see the IDT page
+	uint16_t isr_high;     // The higher 16 bits of the ISR's address
+} __attribute__((packed)) idt_entry_t;
+
+__attribute__((aligned(0x10))) 
+static idt_entry_t idt[256]; // Create an array of IDT entries; aligned for performance
+
+typedef struct {
+	uint16_t	limit;
+	uint32_t	base;
+} __attribute__((packed)) idtr_t;
+
+static idtr_t idtr;
+
+typedef struct {
+   uint32_t ds; /* Data segment selector */
+   uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; /* Pushed by pusha. */
+   uint32_t int_no, err_code; /* Interrupt number and error code (if applicable) */
+   uint32_t eip, cs, eflags, useresp, ss; /* Pushed by the processor automatically */
+} registers_t;
+
+__attribute__((noreturn))
+void exception_handler();
+
+void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags);
+
+extern void* isr_stub_table[];
+ 
+void idt_init(void);
+
+#endif
\ No newline at end of file
diff --git a/src/kernel/platform/interrupts/int_lowlevel.asm b/src/kernel/platform/interrupts/int_lowlevel.asm
new file mode 100644
index 0000000..a030f48
--- /dev/null
+++ b/src/kernel/platform/interrupts/int_lowlevel.asm
@@ -0,0 +1,101 @@
+%macro isr_err_stub 1
+isr_stub_%+%1:
+    ;push byte %1 ; Push interrupt no to stack
+
+    ; 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
+	
+    ; 2. Call C handler
+	call exception_handler
+	
+    ; 3. Restore 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
+	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:
+    ;push byte 0  ; No error occured
+    ;push byte %1 ; Push interrupt no to stack
+    
+    ; 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
+	
+    ; 2. Call C handler
+	call exception_handler
+	
+    ; 3. Restore 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
+
+isr_no_err_stub 0
+isr_no_err_stub 1
+isr_no_err_stub 2
+isr_no_err_stub 3
+isr_no_err_stub 4
+isr_no_err_stub 5
+isr_no_err_stub 6
+isr_no_err_stub 7
+isr_err_stub    8
+isr_no_err_stub 9
+isr_err_stub    10
+isr_err_stub    11
+isr_err_stub    12
+isr_err_stub    13
+isr_err_stub    14
+isr_no_err_stub 15
+isr_no_err_stub 16
+isr_err_stub    17
+isr_no_err_stub 18
+isr_no_err_stub 19
+isr_no_err_stub 20
+isr_no_err_stub 21
+isr_no_err_stub 22
+isr_no_err_stub 23
+isr_no_err_stub 24
+isr_no_err_stub 25
+isr_no_err_stub 26
+isr_no_err_stub 27
+isr_no_err_stub 28
+isr_no_err_stub 29
+isr_err_stub    30
+isr_no_err_stub 31
+
+global isr_stub_table
+isr_stub_table:
+%assign i 0 
+%rep    32 
+    dd isr_stub_%+i ; use DQ instead if targeting 64-bit
+%assign i i+1 
+%endrep
+
diff --git a/src/kernel/platform/types.h b/src/kernel/platform/types.h
deleted file mode 100644
index e18f414..0000000
--- a/src/kernel/platform/types.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef TYPES_H
-#define TYPES_H
-
-typedef unsigned int   u32;
-typedef          int   i32;
-typedef unsigned short u16;
-typedef          short i16;
-typedef unsigned char  u8;
-typedef          char  i8;
-
-#define high16(i32) (i32 & 0xffff)
-#define low16(i32) ((i32>>16) & 0xffff)
-
-#define TRUE 1
-#define FALSE 0
-#define NULL 0
- 
-#endif
\ No newline at end of file
diff --git a/src/kernel/strings.c b/src/kernel/strings.c
index 79897f8..eef8e40 100644
--- a/src/kernel/strings.c
+++ b/src/kernel/strings.c
@@ -1,5 +1,5 @@
 #include "strings.h"
-#include "./platform/types.h"
+#include <stddef.h>
 
 void itoa(int n, char str[]) {
     int i, sign;