diff --git a/.cargo/config.toml b/.cargo/config.toml
new file mode 100644
index 0000000000000000000000000000000000000000..7fa2c556c0349c0b06f51507fd62312b96326c0c
--- /dev/null
+++ b/.cargo/config.toml
@@ -0,0 +1,2 @@
+[target.x86_64-unknown-none]
+runner = "echo"
diff --git a/Cargo.toml b/Cargo.toml
index 3ac3cd0be4bdb24ce430300ac99fd1b92b2ab8d2..f9b0039335e6475860fffe73148c6ae8f20cc2cc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,4 +6,7 @@ build = "build.rs"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
+#[lib]
+#crate-type = ["staticlib"]
+
 [dependencies]
diff --git a/Makefile b/Makefile
index 25638cfdbed6d0b6424bbc51afc2f43421d42eb6..a589445d9908c15377c4e9d9e3f541fa547b4ffe 100644
--- a/Makefile
+++ b/Makefile
@@ -1,48 +1,78 @@
 # target specific
-TARGET          = x86_64-unknown-none
-QEMU            = qemu-system-x86_64
-CONFIG          = x86_64
-EXTRA_RUSTFLAGS =
+TARGET           = x86_64-unknown-none
+QEMU             = qemu-system-x86_64
+CONFIG           = x86_64
+EXTRA_RUSTFLAGS  =
 
-KERNEL          = kernel
-KERNEL_ELF      = target/$(TARGET)/release/$(KERNEL)
-KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(LD_SCRIPT_PATH)/$(LD_SCRIPT) Cargo.toml
-OS_ISO          = target/$(TARGET)/release/$(KERNEL).iso
-LD_SCRIPT_PATH  = $(shell pwd)/src/arch/x86_64
-LD_SCRIPT       = kernel.ld
+KERNEL           = kernel
+KERNEL_ELF       = target/$(TARGET)/release/$(KERNEL)
+DEBUG_KERNEL_ELF = target/$(TARGET)/debug/$(KERNEL)
+KERNEL_LIB       = target/$(TARGET)/release/lib$(KERNEL).a
+DEBUG_KERNEL_LIB = target/$(TARGET)/debug/lib$(KERNEL).a
+OS_ISO           = target/$(TARGET)/release/$(KERNEL).iso
+DEBUG_OS_ISO     = target/$(TARGET)/debug/$(KERNEL).iso
+LD_SCRIPT_PATH   = $(shell pwd)/src/arch/x86_64
+LD_SCRIPT        = kernel.ld
+KERNEL_DEPS      = $(filter-out %: ,$(file < $(KERNEL_ELF).d))
+DEBUG_KERNEL_DEPS= $(filter-out %: ,$(file < $(DEBUG_KERNEL_ELF).d))
+BOOT_SRC         = $(shell find $(LD_SCRIPT_PATH)/boot -name *.asm)
+BOOT_OBJ         = $(patsubst $(LD_SCRIPT_PATH)/boot/%.asm, $(LD_SCRIPT_PATH)/boot/%.o, $(BOOT_SRC))
+CARGO_DEPS       = $(LD_SCRIPT_PATH)/$(LD_SCRIPT) Cargo.toml
 
-RUSTFLAGS   = $(EXTRA_RUSTFLAGS)                 \
-	-C link-arg=--library-path=$(LD_SCRIPT_PATH) \
-	-C link-arg=--script=$(LD_SCRIPT)
+RUSTFLAGS        = $(EXTRA_RUSTFLAGS)              \
+	  -C link-arg=--library-path=$(LD_SCRIPT_PATH) \
+      -C link-arg=--script=$(LD_SCRIPT)
+#      -C relocation-model=static
 
-CARGO_RUSTC = cargo rustc --release	--target=$(TARGET)
+CARGO_BUILD_DEBUG= cargo rustc --target=$(TARGET)
+CARGO_BUILD      = $(CARGO_BUILD_DEBUG) --release --verbose
 
-.PHONY: run
+#DEBUGGER         = lldb $(DEBUG_KERNEL_ELF) -o "gdb-remote localhost:1234"
+DEBUGGER         = gdb  $(DEBUG_KERNEL_ELF) --eval-command "target remote localhost:1234"
+
+
+.PHONY: build run debug
+
+# compile asm
+$(BOOT_OBJ): $(BOOT_SRC) Makefile
+	@echo "Compiling boot assembly"
+	@for asm in ${BOOT_SRC}; do nasm -f elf64 $$asm; done
 
 # compile kernel
-$(KERNEL_ELF): $(KERNEL_ELF_DEPS) Makefile
-	@echo "Compiling kernel ELF"
-	@RUSTFLAGS="$(RUSTFLAGS)" cargo rustc --target=$(TARGET)
-	cp target/$(TARGET)/debug/$(KERNEL) target/$(TARGET)/release/$(KERNEL)
+$(KERNEL_ELF): $(KERNEL_DEPS) $(CARGO_DEPS) Makefile
+	@echo "Compiling kernel lib"
+	RUSTFLAGS="$(RUSTFLAGS)" $(CARGO_BUILD)
+
+# compile debug kernel
+$(DEBUG_KERNEL_ELF): $(DEBUG_KERNEL_DEPS) $(CARGO_DEPS) Makefile
+	@echo "Compiling debug kernel ELF"
+	@RUSTFLAGS="$(RUSTFLAGS)" $(CARGO_BUILD_DEBUG)
 
 # generate grub iso
 $(OS_ISO): $(KERNEL_ELF) Makefile
 	@echo "Generate os iso"
-	@cp $(KERNEL_ELF) iso/boot/kernel
-	@grub-mkrescue /usr/lib/grub/i386-pc -o $@ iso &> /dev/null
+	@cp $< iso/boot/kernel
+	@grub-mkrescue /usr/lib/grub/i386-pc -o $@ iso > /dev/null 2>&1
+
+# generate debug grub iso
+$(DEBUG_OS_ISO): $(DEBUG_KERNEL_ELF) Makefile
+	@echo "Generate debug os iso"
+	@cp $< iso/boot/kernel
+	@grub-mkrescue /usr/lib/grub/i386-pc -o $@ iso > /dev/null 2>&1
 
 # just compile the kernel
 build: $(KERNEL_ELF) Makefile
-	@echo "$(KERNEL_ELF)"
+	@echo "$<"
 
 # compile and run silently
 run: $(OS_ISO) Makefile
 	@echo "Running kernel in QEMU"
-	@$(QEMU) $(OS_ISO) &> /dev/null
+	@$(QEMU) $< &> /dev/null
 
 # compile, run and start gdb
-debug: $(KERNEL_ELF) $(OS_ISO) Makefile
+debug: $(DEBUG_KERNEL_ELF) $(DEBUG_OS_ISO) Makefile
 	@echo "Debugging kernel in QEMU"
-	@$(QEMU) $(OS_ISO) -s &> /dev/null
+	@$(QEMU) $(DEBUG_OS_ISO) -s -no-reboot &> /dev/null
+# wait for qemu to be ready
 	@sleep 1
-	@gdb $(KERNEL_ELF) --eval-command "target remote :1234"
+	@$(DEBUGGER)
diff --git a/src/arch/x86_64/boot.s b/src/arch/x86_64/boot.s
index 2f5d549096b70e23d7f97bd6bd4d90a1d2d1b055..291433ecbe801ea2eae87bd9866705937f4f101b 100644
--- a/src/arch/x86_64/boot.s
+++ b/src/arch/x86_64/boot.s
@@ -1,5 +1,7 @@
 // x86_64 multiboot2 kernel start
 
+KERNEL_BASE = 0xFFFFFFFF80000000;
+                                ;
 /*
     Multiboot header
 */
@@ -26,187 +28,55 @@ header_end:
 /*
     protected mode start
 */
-
-    .section .inittext
+    .section .inittext, "ax"
     .global start
     .code32
 start:
-    // setup stack
-    mov esp, stack_top
-
-    // checks
-    call check_multiboot
-    call check_cpuid
-    call check_long_mode
-
-    // setups
-    call setup_page_tables
-    call enable_paging
-
-    // TODO: GDT before long mode
-    // lgdt [gdt64.pointer]
-    // jmp gdt64.code: start64
-    jmp start64
-
-    jmp halt
-
-error:
-    // print 'ERR: <err>'
-    mov dword ptr [0xb8000], 0x4f524f45
-    mov dword ptr [0xb8004], 0x4f3a4f52
-    mov dword ptr [0xb8008], 0x4f204f20
-    mov byte  ptr [0xb800a], al
-    jmp halt
-
-halt:
-    cli
-    // print 'ZZZ' as halting
-    mov word ptr [0xb8f00], 0x0f5a
-    mov word ptr [0xb8f02], 0x0f5a
-    mov word ptr [0xb8f04], 0x0f5a
-halt_repeat:
-    hlt
-    jmp halt_repeat
-
-/*
-    checks
-*/
-
-// check if booted from a multiboot
-// compliant bootloader
-check_multiboot:
-    cmp eax, 0x36d76289
-    jne .no_multiboot
-    ret
-.no_multiboot:
-    mov al, 'M'
-    jmp error
-
-// check for cpuid instruction availability
-// requirement for checking long mode support
-check_cpuid:
-    pushfd
-    pop eax
-    mov ecx, eax
-    xor eax, 1 << 21
-    push eax
-    popfd
-
-    pushfd
-    pop eax
-    push ecx
-    popfd
-
-    cmp eax, ecx
-    je .no_cpuid
-    ret
-.no_cpuid:
-    mov al, 'C'
-    jmp error
-
-// check for long mode availability
-// requires cpuid instruction availability
-check_long_mode:
-    mov eax, 0x80000000
-    cpuid
-    cmp eax, 0x80000001
-    jb .no_long_mode
-
-    mov eax, 0x80000001
-    cpuid
-    test edx, 1 << 29
-    jz .no_long_mode
-
-    ret
-.no_long_mode:
-    mov al, 'L'
-    jmp error
-
-/*
-    setups - page tables, paging, long mode
-*/
-
-setup_page_tables:
-    mov eax, p3_table
-    or  eax, 0b11 // present, writeable
-    mov [p4_table], eax
-
-    mov eax, p2_table
-    or  eax, 0b11 // present, writeable
-    mov [p3_table], eax
-
-    mov ecx, 0 // counter
-.loop:
-    mov eax, 0x200000 // 2MiB
-    mul ecx
-    or  eax, 0b10000011 // present, writeable, huge page
-    mov [p2_table + ecx * 8], eax
-
-    inc ecx // inc counter
-    cmp ecx, 512 // check if the whole table is mapped
-    jne .loop // if not: continue
-
-    ret
-
-enable_paging:
-    // pass page table location to the cpu
-    mov eax, p4_table
-    mov cr3, eax
-
-    // enable PAE
+    mov multiboot_sig - KERNEL_BASE, eax
+    mov multiboot_ptr - KERNEL_BASE, ebx
     mov eax, cr4
-    or  eax, 1 << 5
-    mov cr4, eax
-
-    // enable long mode
-    mov ecx, 0xC0000080
-    rdmsr
-    or  eax, 1 << 8
-    wrmsr
+    or eax, 0x80|0x20|0x10
+    mov cr3, eax
 
+halt:
     hlt
+    jmp halt
 
-    // enable paging
-    mov eax, cr0
-    or  eax, 1 << 31
-    mov cr0, eax
-
-    ret
 
     .section .text
-    .code64
+    .globl start64
 start64:
-    mov ax, 0
-    mov ss, ax
-    mov ds, ax
-    mov es, ax
-    mov fs, ax
-    mov gs, ax
-
-    // print 'OK'
-    mov dword ptr [0xb8000], 0x2f4b2f4f
-
-    call kernel_main
-    jmp halt
-
-/*
-    memory
-*/
+    mov esp, stack_top
 
     .section .bss
     .align 4096
+    .code64
 // page tables
-p4_table:
+p4_table: // PML4
+    // .quad p3_table + 3
+    // .rept 512 - 3
+    //     .quad
+    // .endr
+    // .quad 0
+    // .quad p2_table + 3
     .skip 4096
-p3_table:
+p3_table: // PDP
+    // .quad
     .skip 4096
-p2_table:
+p2_table: // PD
     .skip 4096
+p1_table: // PT
+
 // 16 KiB stack
 stack_bottom:
     .skip 4096 * 4
 stack_top:
 
+    .section .data
+multiboot_sig:
+    .long 0
+multiboot_ptr:
+    .long 0
 // TODO: global descriptor table
 /*.section .rodata
 gdt64:
diff --git a/src/arch/x86_64/boot.s_all b/src/arch/x86_64/boot.s_all
new file mode 100644
index 0000000000000000000000000000000000000000..6b366d19bcc66acc4781af019c8c09ab6bfd0ce4
--- /dev/null
+++ b/src/arch/x86_64/boot.s_all
@@ -0,0 +1,238 @@
+// x86_64 multiboot2 kernel start
+
+/*
+    Multiboot header
+*/
+
+    .section .multiboot_header, "a"
+    .align 4
+    .global header_start
+header_start:
+    // magic number (multiboot2)
+    .int 0xE85250D6
+    // arch (protected mode i386)
+    .int 0
+    // header length
+    .int header_end - header_start
+    // checksum
+    .int 0x100000000 - (0xe85250d6 + 0 + header_end - header_start)
+
+    // end tag
+    .word 0
+    .word 0
+    .int 8
+header_end:
+
+/*
+    protected mode start
+*/
+    .section .inittext, "ax"
+    .global start
+    .code32
+start:
+    // setup stack
+    mov esp, stack_top
+
+    // checks
+    call check_multiboot
+    call check_cpuid
+    call check_long_mode
+
+    // setups
+    call setup_page_tables
+    call enable_paging
+
+    // TODO: GDT before long mode
+    // lgdt [gdt64.pointer]
+    // jmp gdt64.code: start64
+    jmp start64
+
+    jmp halt
+
+error:
+    // print 'ERR: <err>'
+    mov dword ptr [0xb8000], 0x4f524f45
+    mov dword ptr [0xb8004], 0x4f3a4f52
+    mov dword ptr [0xb8008], 0x4f204f20
+    mov byte  ptr [0xb800a], al
+    jmp halt
+
+halt:
+    cli
+    // print 'ZZZ' as halting
+    mov word ptr [0xb8f00], 0x0f5a
+    mov word ptr [0xb8f02], 0x0f5a
+    mov word ptr [0xb8f04], 0x0f5a
+halt_repeat:
+    hlt
+    jmp halt_repeat
+
+/*
+    checks
+*/
+
+// check if booted from a multiboot
+// compliant bootloader
+check_multiboot:
+    cmp eax, 0x36d76289
+    jne .no_multiboot
+    ret
+.no_multiboot:
+    mov al, 'M'
+    jmp error
+
+// check for cpuid instruction availability
+// requirement for checking long mode support
+check_cpuid:
+    pushfd
+    pop eax
+    mov ecx, eax
+    xor eax, 1 << 21
+    push eax
+    popfd
+
+    pushfd
+    pop eax
+    push ecx
+    popfd
+
+    cmp eax, ecx
+    je .no_cpuid
+    ret
+.no_cpuid:
+    mov al, 'C'
+    jmp error
+
+// check for long mode availability
+// requires cpuid instruction availability
+check_long_mode:
+    mov eax, 0x80000000
+    cpuid
+    cmp eax, 0x80000001
+    jb .no_long_mode
+
+    mov eax, 0x80000001
+    cpuid
+    test edx, 1 << 29
+    jz .no_long_mode
+
+    ret
+.no_long_mode:
+    mov al, 'L'
+    jmp error
+
+/*
+    setups - page tables, paging, long mode
+*/
+
+// btw without these two next lines,
+// the setup_page_tables and .no_long_mode
+// gets corrupted for what ever reason
+//
+// even tho the section is the same already
+// and the bits mode is already 32
+setup_page_tables:
+    mov eax, p3_table
+    or  eax, 0b11 // present, writeable
+    mov [p4_table], eax
+
+    mov eax, p2_table
+    or  eax, 0b11 // present, writeable
+    mov [p3_table], eax
+
+    mov ecx, 0 // counter
+.loop:
+    mov eax, 0x200000 // 2MiB
+    mul ecx
+    or  eax, 0b10000011 // present, writeable, huge page
+    mov [p2_table + ecx * 8], eax
+
+    inc ecx // inc counter
+    cmp ecx, 512 // check if the whole table is mapped
+    jne .loop // if not: continue
+
+    hlt
+    ret
+
+enable_paging:
+    // pass page table location to the cpu
+    mov eax, p4_table
+    mov cr3, eax
+
+    // enable PAE
+    mov eax, cr4
+    or  eax, 1 << 5
+    mov cr4, eax
+
+    // enable long mode
+    mov ecx, 0xC0000080
+    rdmsr
+    or  eax, 1 << 8
+    wrmsr
+
+    // enable paging
+    mov eax, cr0
+    or  eax, 1 << 31
+    mov cr0, eax
+
+    ret
+    nop
+
+/*
+    Start in long mode and jump to the
+    kernel_main in main.rs
+*/
+
+    .section .text
+    .code64
+start64:
+    mov ax, 0
+    mov ss, ax
+    mov ds, ax
+    mov es, ax
+    mov fs, ax
+    mov gs, ax
+
+    // print 'OK'
+    mov dword ptr [0xb8000], 0x2f4b2f4f
+
+    call kernel_main
+    jmp halt
+
+/*
+    memory
+*/
+
+    .section .bss
+    .align 4096
+    .code64
+// page tables
+p4_table: // PML4
+    // .quad p3_table + 3
+    // .rept 512 - 3
+    //     .quad
+    // .endr
+    // .quad 0
+    // .quad p2_table + 3
+    .skip 4096
+p3_table: // PDP
+    // .quad
+    .skip 4096
+p2_table: // PD
+    .skip 4096
+p1_table: // PT
+
+// 16 KiB stack
+stack_bottom:
+    .skip 4096 * 4
+stack_top:
+
+// TODO: global descriptor table
+/*.section .rodata
+gdt64:
+    .long 0 ; zero entry
+.code_segment: equ $ - gdt64
+    .long (1 << 43) | (1 << 44) | (1 << 47) | (1 << 53)
+.pointer:
+    .word $ - gdt64 - 1
+    .long gdt64*/
diff --git a/src/arch/x86_64/boot/.gitignore b/src/arch/x86_64/boot/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..cc5bb740f142b7a2681c2e42692a4d2bb4fc18bd
--- /dev/null
+++ b/src/arch/x86_64/boot/.gitignore
@@ -0,0 +1 @@
+/*.o
diff --git a/src/arch/x86_64/boot/check.asm b/src/arch/x86_64/boot/check.asm
new file mode 100644
index 0000000000000000000000000000000000000000..9a87a1d88a3e022a423dbb2121d7cd73d45c1840
--- /dev/null
+++ b/src/arch/x86_64/boot/check.asm
@@ -0,0 +1,54 @@
+global check_multiboot, check_cpuid, check_long_mode
+extern error
+
+section .text
+bits 32
+
+; multiboot check
+check_multiboot:
+	cmp eax, 0x36d76289
+	jne .no_multiboot
+	ret
+.no_multiboot:
+	mov al, "M"
+	jmp error
+
+; cpuid check
+check_cpuid:
+	pushfd
+	pop eax
+	mov ecx, eax
+	xor eax, 1 << 21
+	push eax
+	popfd
+
+	pushfd
+	pop eax
+	push ecx
+	popfd
+
+	cmp eax, ecx
+	je .no_cpuid
+	ret
+
+.no_cpuid:
+	mov al, "C"
+	jmp error
+
+; long mode check
+check_long_mode:
+	mov eax, 0x80000000
+	cpuid
+	cmp eax, 0x80000001
+	jb .no_long_mode
+
+	mov eax, 0x80000001
+	cpuid
+	test edx, 1 << 29
+	jz .no_long_mode
+
+	ret
+
+.no_long_mode:
+	mov al, "L"
+	jmp error
\ No newline at end of file
diff --git a/src/arch/x86_64/boot/header.asm b/src/arch/x86_64/boot/header.asm
new file mode 100644
index 0000000000000000000000000000000000000000..7f6a0f2dc38181d41f01713941008417147462ee
--- /dev/null
+++ b/src/arch/x86_64/boot/header.asm
@@ -0,0 +1,16 @@
+section .multiboot_header
+header_start:
+	; magic number (multiboot2)
+	dd 0xe85250d6
+	; arch (protected mode i386)
+	dd 0
+	; header length
+	dd header_end - header_start
+	; checksum
+	dd 0x100000000 - (0xe85250d6 + 0 + header_end - header_start)
+
+	; end tag
+	dw 0
+	dw 0
+	dd 8
+header_end:
\ No newline at end of file
diff --git a/src/arch/x86_64/boot/long.asm b/src/arch/x86_64/boot/long.asm
new file mode 100644
index 0000000000000000000000000000000000000000..71ed3bf652865518a49daaff65f90ea8ea630159
--- /dev/null
+++ b/src/arch/x86_64/boot/long.asm
@@ -0,0 +1,18 @@
+global long_mode_start
+extern kernel_main
+
+section .text
+bits 64
+long_mode_start:
+	mov ax, 0
+	mov ss, ax
+	mov ds, ax
+	mov es, ax
+	mov fs, ax
+	mov gs, ax
+
+	; print 'OK'
+	mov dword [0xb8000], 0x2f4b2f4f
+
+	call kernel_main
+	hlt
\ No newline at end of file
diff --git a/src/arch/x86_64/boot/main.asm b/src/arch/x86_64/boot/main.asm
new file mode 100644
index 0000000000000000000000000000000000000000..18927b1f324ed93fda4087c2a3e861567be3e716
--- /dev/null
+++ b/src/arch/x86_64/boot/main.asm
@@ -0,0 +1,39 @@
+global start, error
+extern check_multiboot, check_cpuid, check_long_mode
+extern setup_page_tables, enable_paging
+extern stack_top, gdt64.pointer, gdt64.code_segment
+extern long_mode_start
+
+section .text
+bits 32
+
+start:
+	mov esp, stack_top
+
+	; checks
+	call check_multiboot
+	call check_cpuid
+	call check_long_mode
+
+	; setups
+	call setup_page_tables
+	call enable_paging
+
+	lgdt [gdt64.pointer]
+	jmp gdt64.code_segment: long_mode_start
+	jmp halt
+
+error:
+	; print 'ERR: <err>'
+	mov dword [0xb8000], 0x4f524f45
+	mov dword [0xb8004], 0x4f3a4f52
+	mov dword [0xb8008], 0x4f204f20
+	mov byte  [0xb800a], al
+	jmp halt
+
+halt:
+	; halt the CPU
+	mov word [0xb8f00], 0x0f5a
+	mov word [0xb8f02], 0x0f5a
+	mov word [0xb8f04], 0x0f5a
+	hlt
\ No newline at end of file
diff --git a/src/arch/x86_64/boot/memory.asm b/src/arch/x86_64/boot/memory.asm
new file mode 100644
index 0000000000000000000000000000000000000000..038f6b403698cb422f4bdaffc8d9d2244cabc790
--- /dev/null
+++ b/src/arch/x86_64/boot/memory.asm
@@ -0,0 +1,29 @@
+global page_table_l4, page_table_l3, page_table_l2
+global stack_top
+global gdt64.pointer, gdt64.code_segment
+
+section .bss
+align 4096
+
+; page tables
+page_table_l4:
+	resb 4096
+page_table_l3:
+	resb 4096
+page_table_l2:
+	resb 4096
+
+; stack
+stack_bottom:
+	resb 4096 * 4
+stack_top:
+
+; global descriptor table
+section .rodata
+gdt64:
+	dq 0 ; zero entry
+.code_segment: equ $ - gdt64
+	dq (1 << 43) | (1 << 44) | (1 << 47) | (1 << 53)
+.pointer:
+	dw $ - gdt64 - 1
+	dq gdt64
\ No newline at end of file
diff --git a/src/arch/x86_64/boot/setup.asm b/src/arch/x86_64/boot/setup.asm
new file mode 100644
index 0000000000000000000000000000000000000000..24fc47f475c9768fe5605af1c61a68674e4b024d
--- /dev/null
+++ b/src/arch/x86_64/boot/setup.asm
@@ -0,0 +1,53 @@
+global setup_page_tables, enable_paging
+extern page_table_l4, page_table_l3, page_table_l2
+
+section .text
+bits 32
+
+; page tables
+setup_page_tables:
+	mov eax, page_table_l3
+	or  eax, 0b11 ; present, writeable
+	mov [page_table_l4], eax
+
+	mov eax, page_table_l2
+	or  eax, 0b11 ; present, writeable
+	mov [page_table_l3], eax
+
+	mov ecx, 0 ; counter
+
+.loop:
+	mov eax, 0x200000 ; 2MiB
+	mul ecx,
+	or  eax, 0b10000011 ; present, writeable, huge page
+	mov [page_table_l2 + ecx * 8], eax
+
+	inc ecx ; inc counter
+	cmp ecx, 512 ; check if the whole table is mapped
+	jne .loop ; if not: continue
+
+	ret
+
+; paging
+enable_paging:
+	; pass page table location to the cpu
+	mov eax, page_table_l4
+	mov cr3, eax
+
+	; enable PAE
+	mov eax, cr4
+	or  eax, 1 << 5
+	mov cr4, eax
+
+	; enable long mode
+	mov ecx, 0xC0000080
+	rdmsr
+	or  eax, 1 << 8
+	wrmsr
+
+	; enable paging
+	mov eax, cr0
+	or  eax, 1 << 31
+	mov cr0, eax
+
+	ret
\ No newline at end of file
diff --git a/src/arch/x86_64/kernel.ld b/src/arch/x86_64/kernel.ld
index b1ed7732c34a4037a32e7093402243c93649f43b..c14b4ae7ae4f77eae02761089e617473b5de730e 100644
--- a/src/arch/x86_64/kernel.ld
+++ b/src/arch/x86_64/kernel.ld
@@ -1,28 +1,43 @@
 ENTRY(start)
 OUTPUT_FORMAT(elf64-x86-64)
 
+KERNEL_BASE = 0xFFFFFFFF80000000;
+
 SECTIONS {
-    /* 2 << 20 */
     . = 0x100000;
 
-    .boot : {
-        KEEP(*(.multiboot_header))
+    . += SIZEOF_HEADERS;
+
+    .init : AT(ADDR(.init)) {
+        KEEP( *(.multiboot_header) )
         *(.inittext)
     }
 
-    .text : {
-        *(.text)
+    . += KERNEL_BASE;
+
+    .text ALIGN(0x1000) : AT(ADDR(.text) - KERNEL_BASE) {
+        *(.text .text.*)
+    }
+
+    /* read-only data, page aligned to allow use of the no-execute feature */
+    .rodata ALIGN(0x1000) : AT(ADDR(.rodata) - KERNEL_BASE) {
+        *(.rodata .rodata.*)
     }
 
-    .rodata : {
-        *(.rodata)
+    /* Read-write data, page aligned for the .padata section */
+    .data ALIGN(0x1000) : AT(ADDR(.data) - KERNEL_BASE) {
+        *(.padata)
+        *(.data .data.*)
     }
 
-    .data : {
-        *(.data)
+    /* Zero-initialised data */
+    .bss : AT(ADDR(.bss) - KERNEL_BASE) {
+        *(.bss .bss.*)
     }
 
-    .bss : {
-        *(.bss)
+    kernel_end = .;
+
+    /DISCARD/ : {
+        *(.note .note.*)
     }
 }
diff --git a/src/main.rs b/src/main.rs
index df2c8ad78dcb1e3f5ca49368ea84d09897e60808..4f193bce8387fa7cecb7913db7733d7547e9cb25 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,8 @@
 #![no_std]
 #![no_main]
+#![feature(custom_test_frameworks)]
+#![test_runner(crate::test_runner)]
+#![reexport_test_harness_main = "test_main"]
 
 #[cfg(target_arch = "x86_64")]
 #[path = "arch/x86_64/boot.rs"]
@@ -13,4 +16,17 @@ fn panic_handler(_: &PanicInfo) -> ! {
 }
 
 #[no_mangle]
-fn kernel_main() {}
+pub extern "C" fn kernel_main() {
+    let mut vmem = unsafe { &mut *(0xb8000 as *mut [u8; 4]) };
+    vmem[0] = b'C';
+
+    #[cfg(test)]
+    test_main();
+}
+
+fn test_runner(tests: &[&dyn Fn()]) {}
+
+#[test_case]
+fn test() {
+    assert_eq!(1, 0)
+}