diff --git a/elf.rs b/elf.rs
index a89e17fbdeeb01ad470e9ac4ab7322d7dac6d09a..078e6990830d513af9dc1b2c757c2d4a310cf472 100644
--- a/elf.rs
+++ b/elf.rs
@@ -1,8 +1,8 @@
 //! ELF executables
 
-use collections::{String, Vec};
+use collections::String;
 
-use core::{ptr, str};
+use core::str;
 
 #[cfg(target_arch = "x86")]
 use goblin::elf32::{header, program_header};
@@ -10,9 +10,15 @@ use goblin::elf32::{header, program_header};
 #[cfg(target_arch = "x86_64")]
 use goblin::elf64::{header, program_header};
 
+use arch::externs::{memcpy, memset};
+use arch::paging::{entry, ActivePageTable, Page, VirtualAddress};
+use arch::start::usermode;
+use arch::x86::tlb;
+
 /// An ELF executable
 pub struct Elf<'a> {
     pub data: &'a [u8],
+    header: &'a header::Header
 }
 
 impl<'a> Elf<'a> {
@@ -25,29 +31,125 @@ impl<'a> Elf<'a> {
         } else if data.get(header::EI_CLASS) != Some(&header::ELFCLASS) {
             Err(format!("Elf: Invalid architecture: {:?} != {:?}", data.get(header::EI_CLASS), header::ELFCLASS))
         } else {
-            Ok(Elf { data: data })
+            Ok(Elf {
+                data: data,
+                header: unsafe { &*(data.as_ptr() as usize as *const header::Header) }
+            })
+        }
+    }
+
+    pub fn segments(&'a self) -> ElfSegments<'a> {
+        ElfSegments {
+            data: self.data,
+            header: self.header,
+            i: 0
         }
     }
 
-    pub unsafe fn load_segments(&self) -> Vec<program_header::ProgramHeader> {
-        let mut segments = Vec::new();
+    /// Get the entry field of the header
+    pub fn entry(&self) -> usize {
+        self.header.e_entry as usize
+    }
+
+    /// Test function to run. Remove and replace with proper syscall
+    pub fn run(self) {
+        let mut active_table = unsafe { ActivePageTable::new() };
+
+        for segment in self.segments() {
+            println!("Segment {:X} flags {:X} off {:X} virt {:X} phys {:X} file {} mem {} align {}",
+                        segment.p_type, segment.p_flags, segment.p_offset,
+                        segment.p_vaddr, segment.p_paddr, segment.p_filesz,
+                        segment.p_memsz, segment.p_align);
+
+            if segment.p_type == program_header::PT_LOAD {
+                let start_page = Page::containing_address(VirtualAddress::new(segment.p_vaddr as usize));
+                let end_page = Page::containing_address(VirtualAddress::new((segment.p_vaddr + segment.p_memsz) as usize));
+
+                for page in Page::range_inclusive(start_page, end_page) {
+                    active_table.map(page, entry::NO_EXECUTE | entry::WRITABLE);
+                }
+
+                unsafe {
+                    // Update the page table
+                    tlb::flush_all();
+
+                    // Copy file data
+                    memcpy(segment.p_vaddr as *mut u8,
+                            (self.data.as_ptr() as usize + segment.p_offset as usize) as *const u8,
+                            segment.p_filesz as usize);
+                    // Set BSS
+                    memset((segment.p_vaddr + segment.p_filesz) as *mut u8,
+                            0,
+                            (segment.p_memsz - segment.p_filesz) as usize);
+                }
+
+                let mut flags = entry::NO_EXECUTE | entry::USER_ACCESSIBLE;
 
-        let header = &*(self.data.as_ptr() as usize as *const header::Header);
+                if segment.p_flags & program_header::PF_R == program_header::PF_R {
+                    flags.insert(entry::PRESENT);
+                }
 
-        for i in 0..header.e_phnum {
-            let segment = ptr::read((self.data.as_ptr() as usize + header.e_phoff as usize + i as usize * header.e_phentsize as usize) as *const program_header::ProgramHeader);
+                // W ^ X. If it is executable, do not allow it to be writable, even if requested
+                if segment.p_flags & program_header::PF_X == program_header::PF_X {
+                    flags.remove(entry::NO_EXECUTE);
+                } else if segment.p_flags & program_header::PF_W == program_header::PF_W {
+                    flags.insert(entry::WRITABLE);
+                }
 
-            if segment.p_type == program_header::PT_LOAD || segment.p_type == program_header::PT_TLS {
-                segments.push(segment);
+                for page in Page::range_inclusive(start_page, end_page) {
+                    println!("{:X}: {:?}", page.start_address().get(), flags);
+                    active_table.remap(page, flags);
+                }
+
+                unsafe {
+                    // Update the page table
+                    tlb::flush_all();
+                }
             }
         }
 
-        segments
+        unsafe {
+            // Map stack
+            let start_page = Page::containing_address(VirtualAddress::new(0x80000000));
+            let end_page = Page::containing_address(VirtualAddress::new(0x80000000 + 64*1024 - 1));
+
+            for page in Page::range_inclusive(start_page, end_page) {
+                active_table.map(page, entry::NO_EXECUTE | entry::WRITABLE | entry::USER_ACCESSIBLE);
+            }
+
+            // Update the page table
+            tlb::flush_all();
+
+            // Clear stack
+            memset(0x80000000 as *mut u8, 0, 64 * 1024);
+
+            // Go to usermode
+            usermode(self.entry(), 0x80000000 + 64*1024 - 256);
+        }
     }
+}
 
-    /// Get the entry field of the header
-    pub unsafe fn entry(&self) -> usize {
-        let header = &*(self.data.as_ptr() as usize as *const header::Header);
-        header.e_entry as usize
+pub struct ElfSegments<'a> {
+    data: &'a [u8],
+    header: &'a header::Header,
+    i: usize
+}
+
+impl<'a> Iterator for ElfSegments<'a> {
+    type Item = &'a program_header::ProgramHeader;
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.i < self.header.e_phnum as usize {
+            let item = unsafe {
+                &* ((
+                        self.data.as_ptr() as usize
+                        + self.header.e_phoff as usize
+                        + self.i * self.header.e_phentsize as usize
+                    ) as *const program_header::ProgramHeader)
+            };
+            self.i += 1;
+            Some(item)
+        } else {
+            None
+        }
     }
 }
diff --git a/lib.rs b/lib.rs
index 19d1a4e590f5ab843e9b9ba43e283fdd35480823..d88d92630b281656b4dc62ba1113323fd2310640 100644
--- a/lib.rs
+++ b/lib.rs
@@ -133,6 +133,9 @@ pub extern fn kmain() {
     let pid = syscall::getpid();
     println!("BSP: {:?}", pid);
 
+    let elf = elf::Elf::from(include_bytes!("../init/main")).expect("could not load elf");
+    elf.run();
+
     /*
     if let Ok(_context_lock) = context::contexts_mut().spawn(context_test) {
         print!("Spawned context\n");
@@ -143,7 +146,7 @@ pub extern fn kmain() {
 
     print!("Main halt\n");
     */
-    
+
     loop {
         unsafe { interrupt::enable_and_halt(); }
     }