diff --git a/src/acpi/dmar/mod.rs b/src/acpi/dmar/mod.rs
index 02aac83d5b59ba18b84a7738ed967c15cb47d7a4..e2cf184858cd111964ccf46c480785167ec9e53e 100644
--- a/src/acpi/dmar/mod.rs
+++ b/src/acpi/dmar/mod.rs
@@ -5,6 +5,8 @@ use self::drhd::Drhd;
 use memory::Frame;
 use paging::{entry, ActivePageTable, PhysicalAddress};
 
+use super::{ACPI_TABLE, SDT_POINTERS, get_sdt};
+
 pub mod drhd;
 
 /// The DMA Remapping Table
@@ -17,6 +19,38 @@ pub struct Dmar {
 }
 
 impl Dmar {
+    pub fn init(active_table: &mut ActivePageTable) {
+        if let Some(ref ptrs) = *(SDT_POINTERS.read()) {
+            let dmar = if let Some(dmar_sdt) = ptrs.get("DMAR") {
+                Dmar::new(dmar_sdt)
+            } else {
+                println!("Unable to find DMAR");
+                return;
+            };
+            
+            if let Some(dmar) = dmar {
+                println!("  DMAR: {}: {}", dmar.addr_width, dmar.flags);
+
+                for dmar_entry in dmar.iter() {
+                    println!("      {:?}", dmar_entry);
+                    match dmar_entry {
+                        DmarEntry::Drhd(dmar_drhd) => {
+                            let drhd = dmar_drhd.get(active_table);
+
+                            println!("VER: {:X}", drhd.version);
+                            println!("CAP: {:X}", drhd.cap);
+                            println!("EXT_CAP: {:X}", drhd.ext_cap);
+                            println!("GCMD: {:X}", drhd.gl_cmd);
+                            println!("GSTS: {:X}", drhd.gl_sts);
+                            println!("RT: {:X}", drhd.root_table);
+                        },
+                        _ => ()
+                    }
+                }
+            }
+        }
+    }
+        
     pub fn new(sdt: &'static Sdt) -> Option<Dmar> {
         if &sdt.signature == b"DMAR" && sdt.data_len() >= 12 { //Not valid if no local address and flags
             let addr_width = unsafe { *(sdt.data_address() as *const u8) };
diff --git a/src/acpi/fadt.rs b/src/acpi/fadt.rs
index d40d5a1fc520906a83417c72f73818a7d5f72066..c6ff36c386d329ca46010926110b56326fa8f5b1 100644
--- a/src/acpi/fadt.rs
+++ b/src/acpi/fadt.rs
@@ -1,6 +1,10 @@
 use core::{mem, ptr};
+use collections::string::String;
 
 use super::sdt::Sdt;
+use super::{ACPI_TABLE, SDT_POINTERS, get_sdt};
+
+use paging::ActivePageTable;
 
 #[repr(packed)]
 #[derive(Debug)]
@@ -93,4 +97,26 @@ impl Fadt {
             None
         }
     }
+    
+    pub fn init(active_table: &mut ActivePageTable) {
+        if let Some(ref mut ptrs) = *(SDT_POINTERS.write()) {
+            let fadt = if let Some(fadt_sdt) = ptrs.get("FACP") {
+                Fadt::new(fadt_sdt)
+            } else {
+                println!("Unable to find FADT");
+                return;
+            };
+            
+            if let Some(fadt) = fadt {
+                println!("  FACP: {:X}", fadt.dsdt);
+                    
+                let dsdt_sdt = get_sdt(fadt.dsdt as usize, active_table);
+                let signature = String::from_utf8(dsdt_sdt.signature.to_vec()).expect("Error converting signature to string");
+                ptrs.insert(signature, dsdt_sdt);
+
+                let mut fadt_t = ACPI_TABLE.fadt.write();
+                *fadt_t = Some(fadt);
+            }
+        }
+    }
 }
diff --git a/src/acpi/hpet.rs b/src/acpi/hpet.rs
index 74b14eaaf67349b99828c7304ca160af1c15896d..7b9264874d3d2ec88028fdc5bebe47b5efccb100 100644
--- a/src/acpi/hpet.rs
+++ b/src/acpi/hpet.rs
@@ -1,11 +1,13 @@
 use core::{mem, ptr};
 
-use super::sdt::Sdt;
 use core::intrinsics::{volatile_load, volatile_store};
 
 use memory::Frame;
 use paging::{entry, ActivePageTable, PhysicalAddress, Page, VirtualAddress};
 
+use super::sdt::Sdt;
+use super::{ACPI_TABLE, SDT_POINTERS, get_sdt};
+
 #[repr(packed)]
 #[derive(Clone, Copy, Debug, Default)]
 pub struct GenericAddressStructure {
@@ -33,6 +35,24 @@ pub struct Hpet {
 }
 
 impl Hpet {
+    pub fn init(active_table: &mut ActivePageTable) {
+        if let Some(ref ptrs) = *(SDT_POINTERS.read()) {
+            let hpet = if let Some(hpet_sdt) = ptrs.get("HPET") {
+                Hpet::new(hpet_sdt, active_table)
+            } else {
+                println!("Unable to find HPET");
+                return;
+            };
+            
+            if let Some(hpet) = hpet {
+                println!("  HPET: {:X}", hpet.hpet_number);
+                
+                let mut hpet_t = ACPI_TABLE.hpet.write();
+                *hpet_t = Some(hpet);
+            }
+        }
+    }
+    
     pub fn new(sdt: &'static Sdt, active_table: &mut ActivePageTable) -> Option<Hpet> {
         if &sdt.signature == b"HPET" && sdt.length as usize >= mem::size_of::<Hpet>() {
             let s = unsafe { ptr::read((sdt as *const Sdt) as *const Hpet) };
diff --git a/src/acpi/madt.rs b/src/acpi/madt.rs
index dac16dc7faf66af5c7e0d9d8ce744d621f58f7f1..501bba594ac5f481b0bfce22672cac03d9b059c7 100644
--- a/src/acpi/madt.rs
+++ b/src/acpi/madt.rs
@@ -1,6 +1,27 @@
 use core::mem;
 
+use memory::{allocate_frames, Frame};
+use paging::{entry, ActivePageTable, Page, PhysicalAddress, VirtualAddress};
+
 use super::sdt::Sdt;
+use super::{ACPI_TABLE, SDT_POINTERS, AP_STARTUP, TRAMPOLINE};
+
+use core::intrinsics::{atomic_load, atomic_store};
+use core::sync::atomic::Ordering;
+use collections::btree_map::BTreeMap;
+use collections::string::String;
+use collections::vec::Vec;
+use alloc::boxed::Box;
+
+use syscall::io::{Io, Pio};
+
+use spin::RwLock;
+
+use stop::kstop;
+
+use device::local_apic::LOCAL_APIC;
+use interrupt;
+use start::{kstart_ap, CPU_COUNT, AP_READY};
 
 /// The Multiple APIC Descriptor Table
 #[derive(Debug)]
@@ -11,6 +32,123 @@ pub struct Madt {
 }
 
 impl Madt {
+    pub fn init(active_table: &mut ActivePageTable) {
+        if let Some(ref ptrs) = *(SDT_POINTERS.read()) {
+            let madt = if let Some(madt_sdt) = ptrs.get("APIC") {
+                Madt::new(madt_sdt)
+            } else {
+                println!("Unable to find MADT");
+                return;
+            };
+            
+            if let Some(madt) = madt {
+                println!("  APIC: {:>08X}: {}", madt.local_address, madt.flags);
+
+                let local_apic = unsafe { &mut LOCAL_APIC };
+                let me = local_apic.id() as u8;
+
+                if local_apic.x2 {
+                    println!("    X2APIC {}", me);
+                } else {
+                    println!("    XAPIC {}: {:>08X}", me, local_apic.address);
+                }
+
+                if cfg!(feature = "multi_core"){
+                    let trampoline_frame = Frame::containing_address(PhysicalAddress::new(TRAMPOLINE));
+                    let trampoline_page = Page::containing_address(VirtualAddress::new(TRAMPOLINE));
+
+                    // Map trampoline
+                    let result = active_table.map_to(trampoline_page, trampoline_frame, entry::PRESENT | entry::WRITABLE);
+                    result.flush(active_table);
+
+                    for madt_entry in madt.iter() {
+                        println!("      {:?}", madt_entry);
+                        match madt_entry {
+                            MadtEntry::LocalApic(ap_local_apic) => if ap_local_apic.id == me {
+                                println!("        This is my local APIC");
+                            } else {
+                                if ap_local_apic.flags & 1 == 1 {
+                                    // Increase CPU ID
+                                    CPU_COUNT.fetch_add(1, Ordering::SeqCst);
+
+                                    // Allocate a stack
+                                    let stack_start = allocate_frames(64).expect("no more frames in acpi stack_start").start_address().get() + ::KERNEL_OFFSET;
+                                    let stack_end = stack_start + 64 * 4096;
+
+                                    let ap_ready = TRAMPOLINE as *mut u64;
+                                    let ap_cpu_id = unsafe { ap_ready.offset(1) };
+                                    let ap_page_table = unsafe { ap_ready.offset(2) };
+                                    let ap_stack_start = unsafe { ap_ready.offset(3) };
+                                    let ap_stack_end = unsafe { ap_ready.offset(4) };
+                                    let ap_code = unsafe { ap_ready.offset(5) };
+
+                                    // Set the ap_ready to 0, volatile
+                                    unsafe { atomic_store(ap_ready, 0) };
+                                    unsafe { atomic_store(ap_cpu_id, ap_local_apic.id as u64) };
+                                    unsafe { atomic_store(ap_page_table, active_table.address() as u64) };
+                                    unsafe { atomic_store(ap_stack_start, stack_start as u64) };
+                                    unsafe { atomic_store(ap_stack_end, stack_end as u64) };
+                                    unsafe { atomic_store(ap_code, kstart_ap as u64) };
+                                    AP_READY.store(false, Ordering::SeqCst);
+
+                                    print!("        AP {}:", ap_local_apic.id);
+
+                                    // Send INIT IPI
+                                    {
+                                        let mut icr = 0x4500;
+                                        if local_apic.x2 {
+                                            icr |= (ap_local_apic.id as u64) << 32;
+                                        } else {
+                                            icr |= (ap_local_apic.id as u64) << 56;
+                                        }
+                                        print!(" IPI...");
+                                        local_apic.set_icr(icr);
+                                    }
+
+                                    // Send START IPI
+                                    {
+                                        //Start at 0x0800:0000 => 0x8000. Hopefully the bootloader code is still there
+                                        let ap_segment = (AP_STARTUP >> 12) & 0xFF;
+                                        let mut icr = 0x4600 | ap_segment as u64;
+
+                                        if local_apic.x2 {
+                                            icr |= (ap_local_apic.id as u64) << 32;
+                                        } else {
+                                            icr |= (ap_local_apic.id as u64) << 56;
+                                        }
+
+                                        print!(" SIPI...");
+                                        local_apic.set_icr(icr);
+                                    }
+
+                                    // Wait for trampoline ready
+                                    print!(" Wait...");
+                                    while unsafe { atomic_load(ap_ready) } == 0 {
+                                        interrupt::pause();
+                                    }
+                                    print!(" Trampoline...");
+                                    while ! AP_READY.load(Ordering::SeqCst) {
+                                        interrupt::pause();
+                                    }
+                                    println!(" Ready");
+
+                                    active_table.flush_all();
+                                } else {
+                                    println!("        CPU Disabled");
+                                }
+                            },
+                            _ => ()
+                        }
+                    }
+
+                    // Unmap trampoline
+                    let (result, _frame) = active_table.unmap_return(trampoline_page, false);
+                    result.flush(active_table);
+                }
+            }
+        }
+    }
+    
     pub fn new(sdt: &'static Sdt) -> Option<Madt> {
         if &sdt.signature == b"APIC" && sdt.data_len() >= 8 { //Not valid if no local address and flags
             let local_address = unsafe { *(sdt.data_address() as *const u32) };
diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs
index cdd7e0aaeb0483ab09c3a17a0c32833b85cb4bb7..96447ffdb26889f7a4e0824f5533350cd9b70d95 100644
--- a/src/acpi/mod.rs
+++ b/src/acpi/mod.rs
@@ -5,6 +5,7 @@ use core::intrinsics::{atomic_load, atomic_store};
 use core::sync::atomic::Ordering;
 use collections::btree_map::BTreeMap;
 use collections::string::String;
+use collections::vec::Vec;
 use alloc::boxed::Box;
 
 use syscall::io::{Io, Pio};
@@ -27,6 +28,7 @@ use self::sdt::Sdt;
 use self::xsdt::Xsdt;
 use self::hpet::Hpet;
 use self::rxsdt::Rxsdt;
+use self::rsdp::RSDP;
 
 use self::aml::{is_aml_table, parse_aml_table, AmlError, AmlValue};
 
@@ -39,6 +41,7 @@ mod sdt;
 mod xsdt;
 mod aml;
 mod rxsdt;
+mod rsdp;
 
 const TRAMPOLINE: usize = 0x7E00;
 const AP_STARTUP: usize = TRAMPOLINE + 512;
@@ -235,29 +238,68 @@ fn parse_sdt(sdt: &'static Sdt, active_table: &mut ActivePageTable) {
     }
 }
 
-/// Parse the ACPI tables to gather CPU, interrupt, and timer information
-pub unsafe fn init(active_table: &mut ActivePageTable) {
+fn init_aml_table(sdt: &'static Sdt) {
+    match parse_aml_table(sdt) {
+        Ok(_) => println!(": Parsed"),
+        Err(AmlError::AmlParseError(e)) => println!(": {}", e),
+        Err(AmlError::AmlInvalidOpCode) => println!(": Invalid opcode"),
+        Err(AmlError::AmlValueError) => println!(": Type constraints or value bounds not met"),
+        Err(AmlError::AmlDeferredLoad) => println!(": Deferred load reached top level"),
+        Err(AmlError::AmlFatalError(_, _, _)) => {
+            println!(": Fatal error occurred");
+            unsafe { kstop(); }
+        },
+        Err(AmlError::AmlHardFatal) => {
+            println!(": Fatal error occurred");
+            unsafe { kstop(); }
+        }
+    }
+}
+
+fn init_namespace() {
     {
         let mut namespace = ACPI_TABLE.namespace.write();
         *namespace = Some(BTreeMap::new());
     }
+
+    let dsdt: &'static Sdt = if let Some(ref ptrs) = *(SDT_POINTERS.read()) {
+        if let Some(dsdt_sdt) = ptrs.get("DSDT") {
+            print!("  DSDT");
+            dsdt_sdt
+        } else {
+            println!("No DSDT found");
+            return;
+        }
+    } else {
+        return;
+    };
+
+    init_aml_table(dsdt);
     
-    let start_addr = 0xE0000;
-    let end_addr = 0xFFFFF;
+    let ssdt: &'static Sdt = if let Some(ref ptrs) = *(SDT_POINTERS.read()) {
+        if let Some(ssdt_sdt) = ptrs.get("SSDT") {
+            print!("  SSDT");
+            ssdt_sdt
+        } else {
+            println!("No SSDT found");
+            return;
+        }
+    } else {
+        return;
+    };
 
-    // Map all of the ACPI RSDP space
+    init_aml_table(ssdt);
+}
+
+/// Parse the ACPI tables to gather CPU, interrupt, and timer information
+pub unsafe fn init(active_table: &mut ActivePageTable) {
     {
-        let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr));
-        let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
-        for frame in Frame::range_inclusive(start_frame, end_frame) {
-            let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
-            let result = active_table.map_to(page, frame, entry::PRESENT | entry::NO_EXECUTE);
-            result.flush(active_table);
-        }
+        let mut sdt_ptrs = SDT_POINTERS.write();
+        *sdt_ptrs = Some(BTreeMap::new());
     }
-
+    
     // Search for RSDP
-    if let Some(rsdp) = RSDP::search(start_addr, end_addr) {
+    if let Some(rsdp) = RSDP::get_rsdp(active_table) {
         let rxsdt = get_sdt(rsdp.sdt_address(), active_table);
 
         for &c in rxsdt.signature.iter() {
@@ -273,40 +315,28 @@ pub unsafe fn init(active_table: &mut ActivePageTable) {
             println!("UNKNOWN RSDT OR XSDT SIGNATURE");
             return;
         };
-
-        {
-            let mut rxsdt_ptr = ACPI_TABLE.rxsdt.write();
-            *rxsdt_ptr = Some(rxsdt);
-        }
-
-        {
-            let rxsdt_ptr = ACPI_TABLE.rxsdt.read();
-
-            if let Some(ref rxsdt) = *rxsdt_ptr {
-                rxsdt.map_all(active_table);
-                
-                for sdt_address in rxsdt.iter() {
-                    let sdt = unsafe { &*(sdt_address as *const Sdt) };
-                    parse_sdt(sdt, active_table);
+        
+        rxsdt.map_all(active_table);
+        
+        for sdt_address in rxsdt.iter() {
+            let sdt = unsafe { &*(sdt_address as *const Sdt) };
+            
+            let signature = String::from_utf8(sdt.signature.to_vec()).expect("Error converting signature to string");
+            {
+                if let Some(ref mut ptrs) = *(SDT_POINTERS.write()) {
+                    ptrs.insert(signature, sdt);
                 }
             }
         }
+
+        Fadt::init(active_table);
+        Madt::init(active_table);
+        Dmar::init(active_table);
+        Hpet::init(active_table);
+        init_namespace();
     } else {
         println!("NO RSDP FOUND");
     }
-
-    /* TODO: Cleanup mapping when looking for RSDP
-    // Unmap all of the ACPI RSDP space
-    {
-        let start_frame = Frame::containing_address(PhysicalAddress::new(start_addr));
-        let end_frame = Frame::containing_address(PhysicalAddress::new(end_addr));
-        for frame in Frame::range_inclusive(start_frame, end_frame) {
-            let page = Page::containing_address(VirtualAddress::new(frame.start_address().get()));
-            let result = active_table.unmap(page);
-            result.flush(active_table);
-        }
-    }
-    */
 }
 
 pub fn set_global_s_state(state: u8) {
@@ -337,6 +367,8 @@ pub fn set_global_s_state(state: u8) {
     }
 }
 
+pub static SDT_POINTERS: RwLock<Option<BTreeMap<String, &'static Sdt>>> = RwLock::new(None);
+
 pub struct Acpi {
     pub rxsdt: RwLock<Option<Box<Rxsdt + Send + Sync>>>,
     pub fadt: RwLock<Option<Fadt>>,
@@ -352,40 +384,3 @@ pub static ACPI_TABLE: Acpi = Acpi {
     hpet: RwLock::new(None),
     next_ctx: RwLock::new(0),
 };
-
-/// RSDP
-#[derive(Copy, Clone, Debug)]
-#[repr(packed)]
-pub struct RSDP {
-    signature: [u8; 8],
-    checksum: u8,
-    oemid: [u8; 6],
-    revision: u8,
-    rsdt_address: u32,
-    length: u32,
-    xsdt_address: u64,
-    extended_checksum: u8,
-    reserved: [u8; 3]
-}
-
-impl RSDP {
-    /// Search for the RSDP
-    pub fn search(start_addr: usize, end_addr: usize) -> Option<RSDP> {
-        for i in 0 .. (end_addr + 1 - start_addr)/16 {
-            let rsdp = unsafe { &*((start_addr + i * 16) as *const RSDP) };
-            if &rsdp.signature == b"RSD PTR " {
-                return Some(*rsdp);
-            }
-        }
-        None
-    }
-
-    /// Get the RSDT or XSDT address
-    pub fn sdt_address(&self) -> usize {
-        if self.revision >= 2 {
-            self.xsdt_address as usize
-        } else {
-            self.rsdt_address as usize
-        }
-    }
-}