diff --git a/Cargo.toml b/Cargo.toml
index 35cf50f4a60bfc6112aa0e7f353598862bf2a894..5ee7cdb15f144fc8b826cdfda12bf21776c256ae 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -31,11 +31,13 @@ version = "0.9.0"
 default-features = false
 
 [features]
-default = []
+default = ["qemu_debug"]
 acpi = []
 doc = []
 graphical_debug = []
 live = []
 multi_core = []
 pti = []
+qemu_debug = []
+serial_debug = []
 slab = ["slab_allocator"]
diff --git a/src/arch/x86_64/debug.rs b/src/arch/x86_64/debug.rs
index 2398d92dd9254aeaaf7733ce8b4c194a5be5ab67..5519fd9a4bdc39b0ddba8fc105ffc86f3da144f4 100644
--- a/src/arch/x86_64/debug.rs
+++ b/src/arch/x86_64/debug.rs
@@ -1,41 +1,66 @@
 use core::fmt;
-use spin::MutexGuard;
+use spin::{Mutex, MutexGuard};
 
-use devices::uart_16550::SerialPort;
+#[cfg(feature = "qemu_debug")]
+use syscall::io::Io;
 use syscall::io::Pio;
+#[cfg(feature = "serial_debug")]
+use devices::uart_16550::SerialPort;
 
-use super::device::serial::COM1;
 #[cfg(feature = "graphical_debug")]
 use super::graphical_debug::{DEBUG_DISPLAY, DebugDisplay};
+#[cfg(feature = "serial_debug")]
+use super::device::serial::COM1;
+
+#[cfg(feature = "qemu_debug")]
+pub static QEMU: Mutex<Pio<u8>> = Mutex::new(Pio::<u8>::new(0x402));
 
 pub struct Writer<'a> {
-    serial: MutexGuard<'a, SerialPort<Pio<u8>>>,
     #[cfg(feature = "graphical_debug")]
-    display: MutexGuard<'a, Option<DebugDisplay>>
+    display: MutexGuard<'a, Option<DebugDisplay>>,
+    #[cfg(feature = "qemu_debug")]
+    qemu: MutexGuard<'a, Pio<u8>>,
+    #[cfg(feature = "serial_debug")]
+    serial: MutexGuard<'a, SerialPort<Pio<u8>>>,
 }
 
 impl<'a> Writer<'a> {
     pub fn new() -> Writer<'a> {
         Writer {
-            serial: COM1.lock(),
             #[cfg(feature = "graphical_debug")]
             display: DEBUG_DISPLAY.lock(),
+            #[cfg(feature = "qemu_debug")]
+            qemu: QEMU.lock(),
+            #[cfg(feature = "serial_debug")]
+            serial: COM1.lock(),
         }
     }
-}
 
-impl<'a> fmt::Write for Writer<'a> {
-    #[cfg(not(feature = "graphical_debug"))]
-    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
-        self.serial.write_str(s)
-    }
+    pub fn write(&mut self, buf: &[u8]) {
+        #[cfg(feature = "graphical_debug")]
+        {
+            if let Some(ref mut display) = *self.display {
+                let _ = display.write(buf);
+            }
+        }
 
-    #[cfg(feature = "graphical_debug")]
-    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
-        if let Some(ref mut display) = *self.display {
-            let _ = display.write_str(s);
+        #[cfg(feature = "qemu_debug")]
+        {
+            for &b in buf {
+                self.qemu.write(b);
+            }
         }
 
-        self.serial.write_str(s)
+        #[cfg(feature = "serial_debug")]
+        {
+            self.serial.write(buf);
+        }
+    }
+}
+
+impl<'a> fmt::Write for Writer<'a> {
+    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
+        self.write(s.as_bytes());
+        Ok(())
     }
 }
diff --git a/src/arch/x86_64/graphical_debug/debug.rs b/src/arch/x86_64/graphical_debug/debug.rs
index 21dcf94dc358ad0aa0303525546979151e80a512..c0cbc3c557edd0ac8bc41269267932c541a8efae 100644
--- a/src/arch/x86_64/graphical_debug/debug.rs
+++ b/src/arch/x86_64/graphical_debug/debug.rs
@@ -27,7 +27,7 @@ impl DebugDisplay {
         self.display
     }
 
-    pub fn write(&mut self, c: char) {
+    pub fn write_char(&mut self, c: char) {
         if self.x >= self.w || c == '\n' {
             self.x = 0;
             self.y += 1;
@@ -74,14 +74,10 @@ impl DebugDisplay {
             self.x += 1;
         }
     }
-}
 
-impl fmt::Write for DebugDisplay {
-    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
-        for c in s.chars() {
-            self.write(c);
+    pub fn write(&mut self, buf: &[u8]) {
+        for &b in buf {
+            self.write_char(b as char);
         }
-
-        Ok(())
     }
 }
diff --git a/src/arch/x86_64/interrupt/irq.rs b/src/arch/x86_64/interrupt/irq.rs
index 17adbd0973d82918d7a829f987ed899f27e8c6de..c782f42037b594caaf1fc6d138d2a1e51ae0661b 100644
--- a/src/arch/x86_64/interrupt/irq.rs
+++ b/src/arch/x86_64/interrupt/irq.rs
@@ -5,6 +5,7 @@ use context::timeout;
 use device::pic;
 use device::serial::{COM1, COM2};
 use ipi::{ipi, IpiKind, IpiTarget};
+use scheme::debug::debug_input;
 use time;
 
 //resets to 0 in context::switch()
@@ -74,12 +75,16 @@ interrupt!(cascade, {
 });
 
 interrupt!(com2, {
-    COM2.lock().receive();
+    while let Some(c) = COM2.lock().receive() {
+        debug_input(c);
+    }
     pic::MASTER.ack();
 });
 
 interrupt!(com1, {
-    COM1.lock().receive();
+    while let Some(c) = COM1.lock().receive() {
+        debug_input(c);
+    }
     pic::MASTER.ack();
 });
 
diff --git a/src/devices/uart_16550.rs b/src/devices/uart_16550.rs
index 9e2566fa8bf6a92fd26d48b8b9f9418fb52cc70b..b5e0b2fb5eab5bc8d3008e7f178272a2cf1284cf 100644
--- a/src/devices/uart_16550.rs
+++ b/src/devices/uart_16550.rs
@@ -1,6 +1,3 @@
-use core::fmt::{self, Write};
-
-use scheme::debug::debug_input;
 use syscall::io::{Io, Pio, Mmio, ReadOnly};
 
 bitflags! {
@@ -75,7 +72,7 @@ impl<T: Io<Value = u8>> SerialPort<T> {
         //TODO: Cleanup
         self.int_en.write(0x00);
         self.line_ctrl.write(0x80);
-        self.data.write(0x03);
+        self.data.write(0x01);
         self.int_en.write(0x00);
         self.line_ctrl.write(0x03);
         self.fifo_ctrl.write(0xC7);
@@ -87,37 +84,31 @@ impl<T: Io<Value = u8>> SerialPort<T> {
         LineStsFlags::from_bits_truncate(self.line_sts.read())
     }
 
-    pub fn receive(&mut self) {
-        while self.line_sts().contains(LineStsFlags::INPUT_FULL) {
-            let b = self.data.read();
-            debug_input(b);
+    pub fn receive(&mut self) -> Option<u8> {
+        if self.line_sts().contains(LineStsFlags::INPUT_FULL) {
+            Some(self.data.read())
+        } else {
+            None
         }
     }
 
     pub fn send(&mut self, data: u8) {
-        match data {
-            8 | 0x7F => {
-                while ! self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {}
-                self.data.write(8);
-                while ! self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {}
-                self.data.write(b' ');
-                while ! self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {}
-                self.data.write(8);
-            },
-            _ => {
-                while ! self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {}
-                self.data.write(data);
-            }
-        }
+        while ! self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {}
+        self.data.write(data);
     }
-}
 
-impl<T: Io<Value = u8>> Write for SerialPort<T> {
-    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
-        for byte in s.bytes() {
-            self.send(byte);
+    pub fn write(&mut self, buf: &[u8]) {
+        for &b in buf {
+            match b {
+                8 | 0x7F => {
+                    self.send(8);
+                    self.send(b' ');
+                    self.send(8);
+                },
+                _ => {
+                    self.send(b);
+                }
+            }
         }
-
-        Ok(())
     }
 }
diff --git a/src/scheme/debug.rs b/src/scheme/debug.rs
index 4f1cec5be3453c4fc8a21f2ceae1e6feae52eb55..35de9cc678d51a503a9468dc83e9c7b927c0b317 100644
--- a/src/scheme/debug.rs
+++ b/src/scheme/debug.rs
@@ -1,7 +1,7 @@
 use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
 use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
 
-use device::serial::COM1;
+use arch::debug::Writer;
 use event;
 use scheme::*;
 use sync::WaitQueue;
@@ -76,18 +76,14 @@ impl Scheme for DebugScheme {
     /// Write the `buffer` to the `file`
     ///
     /// Returns the number of bytes written
-    fn write(&self, id: usize, buffer: &[u8]) -> Result<usize> {
+    fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
         let _flags = {
             let handles = handles();
             *handles.get(&id).ok_or(Error::new(EBADF))?
         };
 
-        let mut com = COM1.lock();
-        for &byte in buffer.iter() {
-            com.send(byte);
-        }
-
-        Ok(buffer.len())
+        Writer::new().write(buf);
+        Ok(buf.len())
     }
 
     fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {