From fb0dcc786df279e2fd9c86f4cba208c0be5275fe Mon Sep 17 00:00:00 2001
From: Able <abl3theabove@gmail.com>
Date: Sat, 6 May 2023 06:50:24 -0500
Subject: [PATCH] ableos update

---
 Cargo.lock                           |  94 ++-
 kernel/Cargo.toml                    |   7 +
 kernel/src/arch/x86_64/cpuid.rs      | 924 +++++++++++++++++++++++++++
 kernel/src/arch/x86_64/graphics.rs   |  56 ++
 kernel/src/arch/x86_64/interrupts.rs |  12 +-
 kernel/src/arch/x86_64/logging.rs    |  64 +-
 kernel/src/arch/x86_64/mod.rs        |  83 ++-
 kernel/src/arch/x86_64/pci/mod.rs    | 490 ++++++++++++++
 kernel/src/arch/x86_64/virtio/mod.rs |  38 ++
 kernel/src/device_tree.rs            |  71 ++
 kernel/src/interp/mod.rs             |   4 +-
 kernel/src/kmain.rs                  |  49 +-
 kernel/src/lib.rs                    |   2 +
 kernel/src/utils.rs                  |   1 +
 repbuild/limine.cfg                  |   2 +-
 repbuild/src/main.rs                 |  27 +-
 16 files changed, 1841 insertions(+), 83 deletions(-)
 create mode 100644 kernel/src/arch/x86_64/cpuid.rs
 create mode 100644 kernel/src/arch/x86_64/graphics.rs
 create mode 100644 kernel/src/arch/x86_64/pci/mod.rs
 create mode 100644 kernel/src/arch/x86_64/virtio/mod.rs
 create mode 100644 kernel/src/device_tree.rs
 create mode 100644 kernel/src/utils.rs

diff --git a/Cargo.lock b/Cargo.lock
index 44e9cca..33ed53b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,6 +2,15 @@
 # It is not intended for manual editing.
 version = 3
 
+[[package]]
+name = "able_graphics_library"
+version = "0.1.2"
+source = "git+https://git.ablecorp.us/ableos/ableos_userland#70a65fc10d2caafe370be90eb0e31aa7d9347218"
+dependencies = [
+ "embedded-graphics",
+ "versioning",
+]
+
 [[package]]
 name = "ahash"
 version = "0.7.6"
@@ -65,6 +74,12 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
+[[package]]
+name = "az"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
+
 [[package]]
 name = "bit"
 version = "0.1.1"
@@ -125,7 +140,7 @@ dependencies = [
 [[package]]
 name = "clparse"
 version = "0.1.0"
-source = "git+https://git.ablecorp.us/ableos/ableos_userland#8fa6c705f23ae310e3c4395a61823449ed5a1d02"
+source = "git+https://git.ablecorp.us/ableos/ableos_userland#70a65fc10d2caafe370be90eb0e31aa7d9347218"
 dependencies = [
  "hashbrown 0.13.2",
  "log",
@@ -228,6 +243,29 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
 
+[[package]]
+name = "embedded-graphics"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "750082c65094fbcc4baf9ba31583ce9a8bb7f52cadfb96f6164b1bc7f922f32b"
+dependencies = [
+ "az",
+ "byteorder",
+ "embedded-graphics-core",
+ "float-cmp",
+ "micromath",
+]
+
+[[package]]
+name = "embedded-graphics-core"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8b1239db5f3eeb7e33e35bd10bd014e7b2537b17e071f726a09351431337cfa"
+dependencies = [
+ "az",
+ "byteorder",
+]
+
 [[package]]
 name = "env_logger"
 version = "0.10.0"
@@ -294,6 +332,15 @@ dependencies = [
  "log",
 ]
 
+[[package]]
+name = "float-cmp"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4"
+dependencies = [
+ "num-traits",
+]
+
 [[package]]
 name = "getrandom"
 version = "0.2.8"
@@ -416,9 +463,11 @@ dependencies = [
 name = "kernel"
 version = "0.2.0"
 dependencies = [
+ "able_graphics_library",
  "clparse",
  "crossbeam-queue",
  "derive_more",
+ "embedded-graphics",
  "error-stack 0.3.1",
  "hashbrown 0.13.2",
  "limine",
@@ -429,6 +478,7 @@ dependencies = [
  "spin",
  "uart_16550",
  "versioning",
+ "virtio-drivers",
  "wasmi",
  "x2apic",
  "x86_64",
@@ -492,6 +542,12 @@ version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
+[[package]]
+name = "micromath"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc4010833aea396656c2f91ee704d51a6f1329ec2ab56ffd00bfd56f7481ea94"
+
 [[package]]
 name = "num-integer"
 version = "0.1.45"
@@ -791,11 +847,22 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 [[package]]
 name = "versioning"
 version = "0.1.3"
-source = "git+https://git.ablecorp.us/ableos/ableos_userland#8fa6c705f23ae310e3c4395a61823449ed5a1d02"
+source = "git+https://git.ablecorp.us/ableos/ableos_userland#70a65fc10d2caafe370be90eb0e31aa7d9347218"
 dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "virtio-drivers"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42299957c6f61af586fe3eae398c16ec07f33a02579fa1d41ae96156ce437029"
+dependencies = [
+ "bitflags",
+ "log",
+ "zerocopy",
+]
+
 [[package]]
 name = "volatile"
 version = "0.4.6"
@@ -1108,7 +1175,28 @@ dependencies = [
 [[package]]
 name = "xml"
 version = "0.1.0"
-source = "git+https://git.ablecorp.us/ableos/ableos_userland#8fa6c705f23ae310e3c4395a61823449ed5a1d02"
+source = "git+https://git.ablecorp.us/ableos/ableos_userland#70a65fc10d2caafe370be90eb0e31aa7d9347218"
 dependencies = [
  "serde",
 ]
+
+[[package]]
+name = "zerocopy"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236"
+dependencies = [
+ "byteorder",
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6505e6815af7de1746a08f69c69606bb45695a17149517680f3b2149713b19a3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml
index 9ae4e69..ef59c0e 100644
--- a/kernel/Cargo.toml
+++ b/kernel/Cargo.toml
@@ -5,6 +5,11 @@ version = "0.2.0"
 resolver = "2"
 
 [dependencies]
+
+
+embedded-graphics = "0.7.1"
+
+
 error-stack = { version = "0.3", default-features = false }
 log = "0.4"
 spin = "0.9"
@@ -14,6 +19,7 @@ xml = { git = "https://git.ablecorp.us/ableos/ableos_userland" }
 
 clparse = { git = "https://git.ablecorp.us/ableos/ableos_userland", default-features = false }
 versioning = { git = "https://git.ablecorp.us/ableos/ableos_userland" }
+able_graphics_library = { git = "https://git.ablecorp.us/ableos/ableos_userland" }
 wasmi = { version = "0.29.0", default-features = false }
 hashbrown = "*"
 
@@ -43,6 +49,7 @@ features = [
 limine = { version = "0.1", git = "https://github.com/limine-bootloader/limine-rs" }
 x86_64 = "0.14"
 x2apic = "0.4"
+virtio-drivers = "0.4.0"
 # rdrand = "*"
 rdrand = { version = "0.8", default-features = false }
 
diff --git a/kernel/src/arch/x86_64/cpuid.rs b/kernel/src/arch/x86_64/cpuid.rs
new file mode 100644
index 0000000..98ac9dd
--- /dev/null
+++ b/kernel/src/arch/x86_64/cpuid.rs
@@ -0,0 +1,924 @@
+use core::{arch::asm, fmt, ops::Deref, slice, str};
+
+#[repr(u32)]
+pub enum RequestType {
+    BasicInformation = 0x00000000,
+    VersionInformation = 0x00000001,
+    ThermalPowerManagementInformation = 0x00000006,
+    StructuredExtendedInformation = 0x00000007,
+    ExtendedFunctionInformation = 0x80000000,
+    ExtendedProcessorSignature = 0x80000001,
+    BrandString1 = 0x80000002,
+    BrandString2 = 0x80000003,
+    BrandString3 = 0x80000004,
+    // reserved                       = 0x80000005,
+    CacheLine = 0x80000006,
+    TimeStampCounter = 0x80000007,
+    PhysicalAddressSize = 0x80000008,
+}
+
+pub fn cpuid(code: RequestType) -> (u32, u32, u32, u32) {
+    let eax;
+    let ebx;
+    let ecx;
+    let edx;
+
+    unsafe {
+        asm!(
+            "movq %rbx, {0:r}",
+            "cpuid",
+            "xchgq %rbx, {0:r}",
+            lateout(reg) ebx,
+            inlateout("eax") code as u32 => eax,
+            inlateout("ecx") 0 => ecx,
+            lateout("edx") edx,
+            options(nostack, preserves_flags, att_syntax),
+        );
+    }
+
+    (eax, ebx, ecx, edx)
+}
+
+/// The main entrypoint to the CPU information
+#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
+pub fn master() -> Option<Master> {
+    Some(Master::new())
+}
+
+// This matches the Intel Architecture guide, with bits 31 -> 0.
+// The bit positions are inclusive.
+fn bits_of(val: u32, start_bit: u8, end_bit: u8) -> u32 {
+    let mut silly = 0;
+
+    for _ in start_bit..end_bit + 1 {
+        silly <<= 1;
+        silly |= 1;
+    }
+
+    (val >> start_bit) & silly
+}
+
+pub fn as_bytes(v: &u32) -> &[u8] {
+    let start = v as *const u32 as *const u8;
+    // TODO: use u32::BYTES
+    unsafe { slice::from_raw_parts(start, 4) }
+}
+
+macro_rules! bit {
+    ($reg:ident, {$($idx:expr => $name:ident),+}) => {
+        $(pub fn $name(self) -> bool {
+            ((self.$reg >> $idx) & 1) != 0
+        })+
+    }
+}
+
+macro_rules! dump {
+    ($me:expr, $f: expr, $sname:expr, {$($name:ident),+}) => {
+        $f.debug_struct($sname)
+            $(.field(stringify!($name), &$me.$name()))+
+            .finish()
+    }
+}
+
+macro_rules! delegate_flag {
+    ($item:ident, {$($name:ident),+}) => {
+        $(pub fn $name(&self) -> bool {
+            self.$item.map(|i| i.$name()).unwrap_or(false)
+        })+
+    }
+}
+
+macro_rules! master_attr_reader {
+    ($name:ident, $kind:ty) => {
+        pub fn $name(&self) -> Option<&$kind> {
+            self.$name.as_ref()
+        }
+    };
+}
+
+#[derive(Copy, Clone)]
+pub struct VersionInformation {
+    eax: u32,
+    ebx: u32,
+    ecx: u32,
+    edx: u32,
+}
+
+impl VersionInformation {
+    pub fn new() -> VersionInformation {
+        let (a, b, c, d) = cpuid(RequestType::VersionInformation);
+        VersionInformation {
+            eax: a,
+            ebx: b,
+            ecx: c,
+            edx: d,
+        }
+    }
+
+    pub fn family_id(self) -> u32 {
+        let family_id = bits_of(self.eax, 8, 11);
+        let extended_family_id = bits_of(self.eax, 20, 27);
+
+        if family_id != 0x0F {
+            family_id
+        } else {
+            extended_family_id + family_id
+        }
+    }
+
+    pub fn model_id(self) -> u32 {
+        let family_id = self.family_id();
+        let model_id = bits_of(self.eax, 4, 7);
+        let extended_model_id = bits_of(self.eax, 16, 19);
+
+        if family_id == 0x06 || family_id == 0x0F {
+            (extended_model_id << 4) + model_id
+        } else {
+            model_id
+        }
+    }
+
+    pub fn stepping(self) -> u32 {
+        bits_of(self.eax, 0, 3)
+    }
+
+    fn processor_signature(self) -> u32 {
+        self.eax
+    }
+
+    pub fn brand_string(self) -> Option<&'static str> {
+        let brand_index = bits_of(self.ebx, 0, 7);
+        let processor_signature = self.processor_signature();
+
+        match brand_index {
+            0x00 => None,
+            0x01 => Some("Intel(R) Celeron(R)"),
+            0x02 => Some("Intel(R) Pentium(R) III"),
+            0x03 => {
+                if processor_signature == 0x06B1 {
+                    Some("Intel(R) Celeron(R)")
+                } else {
+                    Some("Intel(R) Pentium(R) III Xeon(R)")
+                }
+            }
+            0x04 => Some("Intel(R) Pentium(R) III"),
+            0x06 => Some("Mobile Intel(R) Pentium(R) III-M"),
+            0x07 => Some("Mobile Intel(R) Celeron(R)"),
+            0x08 => Some("Intel(R) Pentium(R) 4"),
+            0x09 => Some("Intel(R) Pentium(R) 4"),
+            0x0A => Some("Intel(R) Celeron(R)"),
+            0x0B => {
+                if processor_signature == 0x0F13 {
+                    Some("Intel(R) Xeon(R) MP")
+                } else {
+                    Some("Intel(R) Xeon(R)")
+                }
+            }
+            0x0C => Some("Intel(R) Xeon(R) MP"),
+            0x0E => {
+                if processor_signature == 0x0F13 {
+                    Some("Intel(R) Xeon(R)")
+                } else {
+                    Some("Mobile Intel(R) Pentium(R) 4-M")
+                }
+            }
+            0x0F => Some("Mobile Intel(R) Celeron(R)"),
+            0x11 => Some("Mobile Genuine Intel(R)"),
+            0x12 => Some("Intel(R) Celeron(R) M"),
+            0x13 => Some("Mobile Intel(R) Celeron(R)"),
+            0x14 => Some("Intel(R) Celeron(R)"),
+            0x15 => Some("Mobile Genuine Intel(R)"),
+            0x16 => Some("Intel(R) Pentium(R) M"),
+            0x17 => Some("Mobile Intel(R) Celeron(R)"),
+            _ => None,
+        }
+    }
+
+    bit!(ecx, {
+         0 => sse3,
+         1 => pclmulqdq,
+         2 => dtes64,
+         3 => monitor,
+         4 => ds_cpl,
+         5 => vmx,
+         6 => smx,
+         7 => eist,
+         8 => tm2,
+         9 => ssse3,
+        10 => cnxt_id,
+        11 => sdbg,
+        12 => fma,
+        13 => cmpxchg16b,
+        14 => xtpr_update_control,
+        15 => pdcm,
+        // 16 - reserved
+        17 => pcid,
+        18 => dca,
+        19 => sse4_1,
+        20 => sse4_2,
+        21 => x2apic,
+        22 => movbe,
+        23 => popcnt,
+        24 => tsc_deadline,
+        25 => aesni,
+        26 => xsave,
+        27 => osxsave,
+        28 => avx,
+        29 => f16c,
+        30 => rdrand
+        // 31 - unused
+    });
+
+    bit!(edx, {
+        0 => fpu,
+        1 => vme,
+        2 => de,
+        3 => pse,
+        4 => tsc,
+        5 => msr,
+        6 => pae,
+        7 => mce,
+        8 => cx8,
+        9 => apic,
+        // 10 - reserved
+        11 => sep,
+        12 => mtrr,
+        13 => pge,
+        14 => mca,
+        15 => cmov,
+        16 => pat,
+        17 => pse_36,
+        18 => psn,
+        19 => clfsh,
+        // 20 - reserved
+        21 => ds,
+        22 => acpi,
+        23 => mmx,
+        24 => fxsr,
+        25 => sse,
+        26 => sse2,
+        27 => ss,
+        28 => htt,
+        29 => tm,
+        // 30 -reserved
+        31 => pbe
+    });
+}
+
+impl fmt::Debug for VersionInformation {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        dump!(self, f, "VersionInformation", {
+            family_id,
+            model_id,
+            stepping,
+            brand_string,
+            sse3,
+            pclmulqdq,
+            dtes64,
+            monitor,
+            ds_cpl,
+            vmx,
+            smx,
+            eist,
+            tm2,
+            ssse3,
+            cnxt_id,
+            sdbg,
+            fma,
+            cmpxchg16b,
+            xtpr_update_control,
+            pdcm,
+            pcid,
+            dca,
+            sse4_1,
+            sse4_2,
+            x2apic,
+            movbe,
+            popcnt,
+            tsc_deadline,
+            aesni,
+            xsave,
+            osxsave,
+            avx,
+            f16c,
+            rdrand,
+            fpu,
+            vme,
+            de,
+            pse,
+            tsc,
+            msr,
+            pae,
+            mce,
+            cx8,
+            apic,
+            sep,
+            mtrr,
+            pge,
+            mca,
+            cmov,
+            pat,
+            pse_36,
+            psn,
+            clfsh,
+            ds,
+            acpi,
+            mmx,
+            fxsr,
+            sse,
+            sse2,
+            ss,
+            htt,
+            tm,
+            pbe
+        })
+    }
+}
+
+#[derive(Copy, Clone)]
+pub struct ExtendedProcessorSignature {
+    ecx: u32,
+    edx: u32,
+}
+
+impl ExtendedProcessorSignature {
+    fn new() -> ExtendedProcessorSignature {
+        let (_, _, c, d) = cpuid(RequestType::ExtendedProcessorSignature);
+        ExtendedProcessorSignature { ecx: c, edx: d }
+    }
+
+    bit!(ecx, {
+        0 => lahf_sahf_in_64_bit,
+        // 1-4 reserved
+        5 => lzcnt,
+        // 6-7 reserved
+        8 => prefetchw
+        // 9-31 reserved
+    });
+
+    bit!(edx, {
+        // 0-10 reserved
+        11 => syscall_sysret_in_64_bit,
+        // 12-19 reserved
+        20 => execute_disable,
+        // 21-25 reserved
+        26 => gigabyte_pages,
+        27 => rdtscp_and_ia32_tsc_aux,
+        // 28 reserved
+        29 => intel_64_bit_architecture
+        // 30-31 reserved
+    });
+}
+
+impl fmt::Debug for ExtendedProcessorSignature {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        dump!(self, f, "ThermalPowerManagementInformation", {
+            lahf_sahf_in_64_bit,
+            lzcnt,
+            prefetchw,
+            syscall_sysret_in_64_bit,
+            execute_disable,
+            gigabyte_pages,
+            rdtscp_and_ia32_tsc_aux,
+            intel_64_bit_architecture
+        })
+    }
+}
+
+// 3 calls of 4 registers of 4 bytes
+const BRAND_STRING_LENGTH: usize = 3 * 4 * 4;
+
+pub struct BrandString {
+    bytes: [u8; BRAND_STRING_LENGTH],
+}
+
+impl BrandString {
+    fn new() -> BrandString {
+        fn append_bytes(a: RequestType, bytes: &mut [u8]) {
+            let (a, b, c, d) = cpuid(a);
+
+            let result_bytes = as_bytes(&a)
+                .iter()
+                .chain(as_bytes(&b).iter())
+                .chain(as_bytes(&c).iter())
+                .chain(as_bytes(&d).iter());
+
+            for (output, input) in bytes.iter_mut().zip(result_bytes) {
+                *output = *input
+            }
+        }
+
+        let mut brand_string = BrandString {
+            bytes: [0; BRAND_STRING_LENGTH],
+        };
+        append_bytes(RequestType::BrandString1, &mut brand_string.bytes[0..]);
+        append_bytes(RequestType::BrandString2, &mut brand_string.bytes[16..]);
+        append_bytes(RequestType::BrandString3, &mut brand_string.bytes[32..]);
+        brand_string
+    }
+}
+
+impl Clone for BrandString {
+    fn clone(&self) -> Self {
+        let mut bytes = [0; BRAND_STRING_LENGTH];
+        for (d, s) in bytes.iter_mut().zip(self.bytes.iter()) {
+            *d = *s;
+        }
+        BrandString { bytes: bytes }
+    }
+}
+
+impl Deref for BrandString {
+    type Target = str;
+
+    fn deref(&self) -> &str {
+        let nul_terminator = self.bytes.iter().position(|&b| b == 0).unwrap_or(0);
+        let usable_bytes = &self.bytes[..nul_terminator];
+        unsafe { str::from_utf8_unchecked(usable_bytes) }.trim()
+    }
+}
+
+impl fmt::Display for BrandString {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        (self as &str).fmt(f)
+    }
+}
+
+impl fmt::Debug for BrandString {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        (self as &str).fmt(f)
+    }
+}
+
+#[derive(Copy, Clone)]
+pub struct ThermalPowerManagementInformation {
+    eax: u32,
+    ebx: u32,
+    ecx: u32,
+}
+
+impl ThermalPowerManagementInformation {
+    fn new() -> ThermalPowerManagementInformation {
+        let (a, b, c, _) = cpuid(RequestType::ThermalPowerManagementInformation);
+        ThermalPowerManagementInformation {
+            eax: a,
+            ebx: b,
+            ecx: c,
+        }
+    }
+
+    bit!(eax, {
+        0 => digital_temperature_sensor,
+        1 => intel_turbo_boost,
+        2 => arat,
+        // 3 - reserved
+        4 => pln,
+        5 => ecmd,
+        6 => ptm,
+        7 => hwp,
+        8 => hwp_notification,
+        9 => hwp_activity_window,
+        10 => hwp_energy_performance_preference,
+        // 12 - reserved
+        13 => hdc
+    });
+
+    pub fn number_of_interrupt_thresholds(self) -> u32 {
+        bits_of(self.ebx, 0, 3)
+    }
+
+    bit!(ecx, {
+        0 => hardware_coordination_feedback,
+        // 1-2 - reserved
+        3 => performance_energy_bias
+    });
+}
+
+impl fmt::Debug for ThermalPowerManagementInformation {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        dump!(self, f, "ThermalPowerManagementInformation", {
+            digital_temperature_sensor,
+            intel_turbo_boost,
+            arat,
+            pln,
+            ecmd,
+            ptm,
+            hwp,
+            hwp_notification,
+            hwp_activity_window,
+            hwp_energy_performance_preference,
+            hdc,
+
+            number_of_interrupt_thresholds,
+
+            hardware_coordination_feedback,
+            performance_energy_bias
+        })
+    }
+}
+
+#[derive(Copy, Clone)]
+pub struct StructuredExtendedInformation {
+    ebx: u32,
+    ecx: u32,
+}
+
+impl StructuredExtendedInformation {
+    fn new() -> StructuredExtendedInformation {
+        let (_, b, c, _) = cpuid(RequestType::StructuredExtendedInformation);
+        StructuredExtendedInformation { ebx: b, ecx: c }
+    }
+
+    bit!(ebx, {
+        0 => fsgsbase,
+        1 => ia32_tsc_adjust_msr,
+        // 2 - reserved
+        3 => bmi1,
+        4 => hle,
+        5 => avx2,
+        // 6 - reserved
+        7 => smep,
+        8 => bmi2,
+        9 => enhanced_rep_movsb_stosb,
+        10 => invpcid,
+        11 => rtm,
+        12 => pqm,
+        13 => deprecates_fpu_cs_ds,
+        // 14 - reserved
+        15 => pqe,
+        // 16-17 - reserved
+        18 => rdseed,
+        19 => adx,
+        20 => smap,
+        // 21-24 - reserved
+        25 => intel_processor_trace
+        // 26-31 - reserved
+    });
+
+    bit!(ecx, {
+        0 => prefetchwt1
+    });
+}
+
+impl fmt::Debug for StructuredExtendedInformation {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        dump!(self, f, "StructuredExtendedInformation", {
+            fsgsbase,
+            ia32_tsc_adjust_msr,
+            bmi1,
+            hle,
+            avx2,
+            smep,
+            bmi2,
+            enhanced_rep_movsb_stosb,
+            invpcid,
+            rtm,
+            pqm,
+            deprecates_fpu_cs_ds,
+            pqe,
+            rdseed,
+            adx,
+            smap,
+            intel_processor_trace,
+            prefetchwt1
+        })
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum CacheLineAssociativity {
+    Disabled,
+    DirectMapped,
+    TwoWay,
+    FourWay,
+    EightWay,
+    SixteenWay,
+    Full,
+}
+
+#[derive(Copy, Clone)]
+pub struct CacheLine(u32);
+
+impl CacheLine {
+    fn new() -> CacheLine {
+        let (_, _, c, _) = cpuid(RequestType::CacheLine);
+        CacheLine(c)
+    }
+
+    pub fn cache_line_size(self) -> u32 {
+        bits_of(self.0, 0, 7)
+    }
+
+    pub fn l2_associativity(self) -> Option<CacheLineAssociativity> {
+        match bits_of(self.0, 12, 15) {
+            0x00 => Some(CacheLineAssociativity::Disabled),
+            0x01 => Some(CacheLineAssociativity::DirectMapped),
+            0x02 => Some(CacheLineAssociativity::TwoWay),
+            0x04 => Some(CacheLineAssociativity::FourWay),
+            0x06 => Some(CacheLineAssociativity::EightWay),
+            0x08 => Some(CacheLineAssociativity::SixteenWay),
+            0x0F => Some(CacheLineAssociativity::Full),
+            _ => None,
+        }
+    }
+
+    pub fn cache_size(self) -> u32 {
+        bits_of(self.0, 16, 31)
+    }
+}
+
+impl fmt::Debug for CacheLine {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        dump!(self, f, "CacheLine", {
+            cache_line_size,
+            l2_associativity,
+            cache_size
+        })
+    }
+}
+
+#[derive(Copy, Clone)]
+pub struct TimeStampCounter {
+    edx: u32,
+}
+
+impl TimeStampCounter {
+    fn new() -> TimeStampCounter {
+        let (_, _, _, d) = cpuid(RequestType::TimeStampCounter);
+        TimeStampCounter { edx: d }
+    }
+
+    bit!(edx, {
+        // 0-7 - reserved
+        8 => invariant_tsc
+        // 9-31 - reserved
+    });
+}
+
+impl fmt::Debug for TimeStampCounter {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        dump!(self, f, "TimeStampCounter", { invariant_tsc })
+    }
+}
+
+#[derive(Copy, Clone)]
+pub struct PhysicalAddressSize(u32);
+
+impl PhysicalAddressSize {
+    fn new() -> PhysicalAddressSize {
+        let (a, _, _, _) = cpuid(RequestType::PhysicalAddressSize);
+        PhysicalAddressSize(a)
+    }
+
+    pub fn physical_address_bits(self) -> u32 {
+        bits_of(self.0, 0, 7)
+    }
+
+    pub fn linear_address_bits(self) -> u32 {
+        bits_of(self.0, 8, 15)
+    }
+}
+
+impl fmt::Debug for PhysicalAddressSize {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        dump!(self, f, "PhysicalAddressSize", {
+            physical_address_bits,
+            linear_address_bits
+        })
+    }
+}
+
+/// Information about the currently running processor
+///
+/// Feature flags match the feature mnemonic listed in the Intel
+/// Instruction Set Reference. This struct provides a facade for flags
+/// so the consumer doesn't need to worry about which particular CPUID
+/// leaf provides the information.
+///
+/// For data beyond simple feature flags, you will need to retrieve
+/// the nested struct and call the appropriate methods on it.
+#[derive(Debug, Clone)]
+pub struct Master {
+    // TODO: Rename struct
+    version_information: Option<VersionInformation>,
+    thermal_power_management_information: Option<ThermalPowerManagementInformation>,
+    structured_extended_information: Option<StructuredExtendedInformation>,
+    extended_processor_signature: Option<ExtendedProcessorSignature>,
+    brand_string: Option<BrandString>,
+    cache_line: Option<CacheLine>,
+    time_stamp_counter: Option<TimeStampCounter>,
+    physical_address_size: Option<PhysicalAddressSize>,
+}
+
+impl Master {
+    pub fn new() -> Master {
+        fn when_supported<F, T>(max: u32, kind: RequestType, then: F) -> Option<T>
+        where
+            F: FnOnce() -> T,
+        {
+            if max >= kind as u32 {
+                Some(then())
+            } else {
+                None
+            }
+        }
+
+        let (max_value, _, _, _) = cpuid(RequestType::BasicInformation);
+
+        let vi = when_supported(max_value, RequestType::VersionInformation, || {
+            VersionInformation::new()
+        });
+        let tpm = when_supported(
+            max_value,
+            RequestType::ThermalPowerManagementInformation,
+            || ThermalPowerManagementInformation::new(),
+        );
+        let sei = when_supported(
+            max_value,
+            RequestType::StructuredExtendedInformation,
+            || StructuredExtendedInformation::new(),
+        );
+
+        // Extended information
+
+        let (max_value, _, _, _) = cpuid(RequestType::ExtendedFunctionInformation);
+
+        let eps = when_supported(max_value, RequestType::ExtendedProcessorSignature, || {
+            ExtendedProcessorSignature::new()
+        });
+        let brand_string =
+            when_supported(max_value, RequestType::BrandString3, || BrandString::new());
+        let cache_line = when_supported(max_value, RequestType::CacheLine, || CacheLine::new());
+        let tsc = when_supported(max_value, RequestType::TimeStampCounter, || {
+            TimeStampCounter::new()
+        });
+        let pas = when_supported(max_value, RequestType::PhysicalAddressSize, || {
+            PhysicalAddressSize::new()
+        });
+
+        Master {
+            version_information: vi,
+            thermal_power_management_information: tpm,
+            structured_extended_information: sei,
+            extended_processor_signature: eps,
+            brand_string: brand_string,
+            cache_line: cache_line,
+            time_stamp_counter: tsc,
+            physical_address_size: pas,
+        }
+    }
+
+    master_attr_reader!(version_information, VersionInformation);
+    master_attr_reader!(
+        thermal_power_management_information,
+        ThermalPowerManagementInformation
+    );
+    master_attr_reader!(
+        structured_extended_information,
+        StructuredExtendedInformation
+    );
+    master_attr_reader!(extended_processor_signature, ExtendedProcessorSignature);
+    master_attr_reader!(cache_line, CacheLine);
+    master_attr_reader!(time_stamp_counter, TimeStampCounter);
+    master_attr_reader!(physical_address_size, PhysicalAddressSize);
+
+    pub fn brand_string(&self) -> Option<&str> {
+        self.brand_string
+            .as_ref()
+            .map(|bs| bs as &str)
+            .or(self.version_information.and_then(|vi| vi.brand_string()))
+    }
+
+    delegate_flag!(version_information, {
+        sse3,
+        pclmulqdq,
+        dtes64,
+        monitor,
+        ds_cpl,
+        vmx,
+        smx,
+        eist,
+        tm2,
+        ssse3,
+        cnxt_id,
+        sdbg,
+        fma,
+        cmpxchg16b,
+        xtpr_update_control,
+        pdcm,
+        pcid,
+        dca,
+        sse4_1,
+        sse4_2,
+        x2apic,
+        movbe,
+        popcnt,
+        tsc_deadline,
+        aesni,
+        xsave,
+        osxsave,
+        avx,
+        f16c,
+        rdrand,
+        fpu,
+        vme,
+        de,
+        pse,
+        tsc,
+        msr,
+        pae,
+        mce,
+        cx8,
+        apic,
+        sep,
+        mtrr,
+        pge,
+        mca,
+        cmov,
+        pat,
+        pse_36,
+        psn,
+        clfsh,
+        ds,
+        acpi,
+        mmx,
+        fxsr,
+        sse,
+        sse2,
+        ss,
+        htt,
+        tm,
+        pbe
+    });
+
+    delegate_flag!(thermal_power_management_information, {
+        digital_temperature_sensor,
+        intel_turbo_boost,
+        arat,
+        pln,
+        ecmd,
+        ptm,
+        hwp,
+        hwp_notification,
+        hwp_activity_window,
+        hwp_energy_performance_preference,
+        hdc,
+        hardware_coordination_feedback,
+        performance_energy_bias
+    });
+
+    delegate_flag!(structured_extended_information, {
+        fsgsbase,
+        ia32_tsc_adjust_msr,
+        bmi1,
+        hle,
+        avx2,
+        smep,
+        bmi2,
+        enhanced_rep_movsb_stosb,
+        invpcid,
+        rtm,
+        pqm,
+        deprecates_fpu_cs_ds,
+        pqe,
+        rdseed,
+        adx,
+        smap,
+        intel_processor_trace,
+        prefetchwt1
+    });
+
+    delegate_flag!(extended_processor_signature, {
+        lahf_sahf_in_64_bit,
+        lzcnt,
+        prefetchw,
+        syscall_sysret_in_64_bit,
+        execute_disable,
+        gigabyte_pages,
+        rdtscp_and_ia32_tsc_aux,
+        intel_64_bit_architecture
+    });
+
+    delegate_flag!(time_stamp_counter, { invariant_tsc });
+}
+/*
+cfg_if! {
+    if #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] {
+
+        #[test]
+        fn basic_genuine_intel() {
+            let (_, b, c, d) = cpuid(RequestType::BasicInformation);
+
+            assert_eq!(b"Genu", as_bytes(&b));
+            assert_eq!(b"ntel", as_bytes(&c));
+            assert_eq!(b"ineI", as_bytes(&d));
+        }
+
+        #[test]
+        fn brand_string_contains_intel() {
+            assert!(master().unwrap().brand_string().unwrap().contains("Intel(R)"))
+        }
+
+    } else {}
+}
+*/
diff --git a/kernel/src/arch/x86_64/graphics.rs b/kernel/src/arch/x86_64/graphics.rs
new file mode 100644
index 0000000..3ad4346
--- /dev/null
+++ b/kernel/src/arch/x86_64/graphics.rs
@@ -0,0 +1,56 @@
+use virtio_drivers::transport::Transport;
+
+use crate::arch::virtio::AbleosHal;
+
+use {embedded_graphics::pixelcolor::Rgb888, virtio_drivers::device::gpu::VirtIOGpu};
+
+use {
+    able_graphics_library::raw_pixel::Display,
+    embedded_graphics::prelude::*,
+    limine::FramebufferRequest,
+    spin::{Lazy, Mutex},
+};
+
+pub static DISPLAY: Lazy<Mutex<Display>> = Lazy::new(|| {
+    static FB_REQ: FramebufferRequest = FramebufferRequest::new(0);
+    let fb1 = &FB_REQ.get_response().get().unwrap().framebuffers()[0];
+    let m = Mutex::new(Display {
+        fb:    fb1.address.as_ptr().unwrap().cast(),
+        size:  Size::new(fb1.width as u32, fb1.height as u32),
+        color: Rgb888::WHITE,
+    });
+    log::info!("Graphics initialised");
+    m
+});
+
+pub fn init() {
+    Lazy::force(&DISPLAY);
+}
+pub fn virtio_gpu<T: Transport>(transport: T) {
+    let mut gpu = VirtIOGpu::<AbleosHal, T>::new(transport).expect("failed to create gpu driver");
+    let (width, height) = gpu.resolution().expect("failed to get resolution");
+    let width = width as usize;
+    let height = height as usize;
+    log::info!("GPU resolution is {}x{}", width, height);
+    let fb = gpu.setup_framebuffer().expect("failed to get fb");
+    for y in 0..height {
+        for x in 0..width {
+            let idx = (y * width + x) * 4;
+            fb[idx] = x as u8;
+            fb[idx + 1] = y as u8;
+            fb[idx + 2] = (x + y) as u8;
+        }
+    }
+    gpu.flush().expect("failed to flush");
+    //delay some time
+    log::info!("virtio-gpu show graphics....");
+    for _ in 0..100000 {
+        for _ in 0..100000 {
+            unsafe {
+                core::arch::asm!("nop");
+            }
+        }
+    }
+
+    log::info!("virtio-gpu test finished");
+}
diff --git a/kernel/src/arch/x86_64/interrupts.rs b/kernel/src/arch/x86_64/interrupts.rs
index 090f031..651b155 100644
--- a/kernel/src/arch/x86_64/interrupts.rs
+++ b/kernel/src/arch/x86_64/interrupts.rs
@@ -1,6 +1,10 @@
-use spin::{Lazy, Mutex};
-use x2apic::lapic::{LocalApic, LocalApicBuilder};
-use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
+use {
+    spin::{Lazy, Mutex},
+    x2apic::lapic::{LocalApic, LocalApicBuilder},
+    x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode},
+};
+
+use log::info;
 
 use crate::interp::wasm;
 
@@ -14,6 +18,7 @@ pub unsafe fn init() {
 #[repr(u8)]
 enum Interrupt {
     Timer = 32,
+    Keyboard = 33,
     ApicErr = u8::MAX - 1,
     Spurious = u8::MAX,
 }
@@ -46,6 +51,7 @@ static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
     idt[Interrupt::Spurious as usize].set_handler_fn(spurious);
 
     idt[Interrupt::Timer as usize].set_handler_fn(timer);
+
     idt
 });
 
diff --git a/kernel/src/arch/x86_64/logging.rs b/kernel/src/arch/x86_64/logging.rs
index 5f64096..e01a506 100644
--- a/kernel/src/arch/x86_64/logging.rs
+++ b/kernel/src/arch/x86_64/logging.rs
@@ -1,46 +1,48 @@
 //! Logging (as in terms of console / serial output)
 
-use core::fmt::Write;
-use limine::{TerminalRequest, TerminalResponse};
-use spin::{Lazy, Mutex};
-use uart_16550::SerialPort;
+use {
+    core::fmt::Write,
+    limine::{TerminalRequest, TerminalResponse},
+    spin::{Lazy, Mutex},
+    uart_16550::SerialPort,
+};
 
-static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3f8) });
-static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));
+static SERIAL_CONSOLE: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) });
+// static TERMINAL_LOGGER: Lazy<Mutex<TermLogger>> = Lazy::new(|| Mutex::new(TermLogger::new()));
 
 pub fn init() {
     SERIAL_CONSOLE.lock().init();
-    Lazy::force(&TERMINAL_LOGGER);
+    // Lazy::force(&TERMINAL_LOGGER);
 }
 
 pub fn log(args: core::fmt::Arguments<'_>) -> core::fmt::Result {
     x86_64::instructions::interrupts::without_interrupts(|| {
-        TERMINAL_LOGGER.lock().write_fmt(args)?;
+        // TERMINAL_LOGGER.lock().write_fmt(args)?;
         SERIAL_CONSOLE.lock().write_fmt(args)
     })
 }
 
-struct TermLogger(&'static TerminalResponse);
-unsafe impl Send for TermLogger {}
-impl TermLogger {
-    pub fn new() -> Self {
-        static TERM_REQ: TerminalRequest = TerminalRequest::new(0);
-        Self(
-            TERM_REQ
-                .get_response()
-                .get()
-                .expect("failed to get terminal response"),
-        )
-    }
-}
+// struct TermLogger(&'static TerminalResponse);
+// unsafe impl Send for TermLogger {}
+// impl TermLogger {
+//     pub fn new() -> Self {
+//         static TERM_REQ: TerminalRequest = TerminalRequest::new(0);
+//         Self(
+//             TERM_REQ
+//                 .get_response()
+//                 .get()
+//                 .expect("failed to get terminal response"),
+//         )
+//     }
+// }
 
-impl Write for TermLogger {
-    fn write_str(&mut self, s: &str) -> core::fmt::Result {
-        if let (Some(w), ts) = (self.0.write(), self.0.terminals()) {
-            for term in ts {
-                w(term, s);
-            }
-        }
-        Ok(())
-    }
-}
+// impl Write for TermLogger {
+//     fn write_str(&mut self, s: &str) -> core::fmt::Result {
+//         if let (Some(w), ts) = (self.0.write(), self.0.terminals()) {
+//             for term in ts {
+//                 w(term, s);
+//             }
+//         }
+//         Ok(())
+//     }
+// }
diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs
index b889364..f12f8fd 100644
--- a/kernel/src/arch/x86_64/mod.rs
+++ b/kernel/src/arch/x86_64/mod.rs
@@ -1,15 +1,26 @@
+use {limine::SmpRequest, xml::XMLElement};
+
+use embedded_graphics::pixelcolor::Rgb888;
+
+use crate::{arch::x86_64::graphics::DISPLAY, kmain::DEVICE_TREE};
+
 pub mod memory;
 
+mod cpuid;
 mod gdt;
+mod graphics;
 pub(crate) mod interrupts;
 mod logging;
+pub mod pci;
+pub mod virtio;
 
-pub use logging::log;
-pub use memory::PAGE_SIZE;
+pub use {logging::log, memory::PAGE_SIZE};
 
-use crate::allocator;
-use limine::{HhdmRequest, KernelFileRequest, MemmapRequest, ModuleRequest};
-use x86_64::VirtAddr;
+use {
+    crate::allocator,
+    limine::{HhdmRequest, KernelFileRequest, MemmapRequest, ModuleRequest},
+    x86_64::VirtAddr,
+};
 
 extern "C" {
     fn _initial_kernel_heap_start();
@@ -51,6 +62,65 @@ unsafe extern "C" fn _kernel_start() -> ! {
     static KFILE_REQ: KernelFileRequest = KernelFileRequest::new(0);
     static MOD_REQ: ModuleRequest = ModuleRequest::new(0);
 
+    static SMP: SmpRequest = SmpRequest::new(0);
+    let smp = SMP.get_response().get().unwrap();
+    use crate::alloc::string::ToString;
+
+    let cpuinfo = cpuid::master().unwrap();
+    let brand_string = cpuinfo.brand_string().unwrap_or("Unknown").to_string();
+    DEVICE_TREE.force_unlock();
+
+    pci::init();
+
+    let mut dt = DEVICE_TREE.lock();
+
+    let cpus = dt.devices.get_mut("CPUs").unwrap();
+    let mut cpu = XMLElement::new("cpu");
+    let core_count = smp.cpu_count.to_string();
+    cpu.set_attribute("core count", core_count);
+    cpu.set_attribute("brand string", brand_string);
+
+    let cpu_speed = 0;
+
+    cpu.set_attribute("speed", "Unknown");
+
+    if false {
+        // disable()     // disable interrupts (if still not done)
+        let i = 0;
+        let start = cpuinfo.time_stamp_counter();
+
+        log::info!("{:?}", start.unwrap().invariant_tsc());
+        for x in 0..1000 {}
+        let end = cpuinfo.time_stamp_counter();
+    }
+
+    let mut cpu_features = xml::XMLElement::new("CPU Features");
+    {
+        let x2 = cpuinfo.x2apic();
+        let apic = cpuinfo.apic();
+        let avx = cpuinfo.avx();
+
+        cpu_features.set_attribute("apic", apic.to_string());
+        cpu_features.set_attribute("avx", apic.to_string());
+        cpu_features.set_attribute("x2apic", x2.to_string());
+    }
+
+    cpu.set_child(cpu_features);
+    cpus.push(cpu);
+    drop(dt);
+
+    // Graphics test
+    {
+        let mut dis = DISPLAY.lock();
+        use {able_graphics_library::raw_pixel, embedded_graphics::prelude::RgbColor};
+
+        dis.set_color(Rgb888::GREEN);
+
+        dis.line(1, 1, 10, 10, 4);
+        dis.line(1, 200, 100, 10, 1);
+        dis.line(1, 1, 200, 10, 1);
+    }
+
     crate::kmain::kmain(
         KFILE_REQ
             .get_response()
@@ -84,8 +154,7 @@ pub fn sloop() -> ! {
 }
 
 pub fn hardware_random_u64() -> u64 {
-    use log::trace;
-    use rdrand::RdRand;
+    use {log::trace, rdrand::RdRand};
     let gen = RdRand::new().unwrap();
     let ret = gen.try_next_u64().unwrap();
     trace!("Random {}", ret);
diff --git a/kernel/src/arch/x86_64/pci/mod.rs b/kernel/src/arch/x86_64/pci/mod.rs
new file mode 100644
index 0000000..eb1696f
--- /dev/null
+++ b/kernel/src/arch/x86_64/pci/mod.rs
@@ -0,0 +1,490 @@
+#[derive(Copy, Clone, Debug)]
+/// A struct containing info about a PCI device.
+pub struct PciDeviceInfo {
+    pub header_type: u8,
+    pub device: u8,
+    pub bus: u8,
+    pub device_id: DeviceID,
+    pub full_class: PciFullClass,
+    pub rev_id: u8,
+}
+use crate::alloc::string::ToString;
+/// Enumerate PCI devices and run initialisation routines on ones we support
+pub fn init() {
+    let mut dt = DEVICE_TREE.lock();
+    dt.devices
+        .insert("Unidentified PCI".to_string(), alloc::vec![]);
+    let mut devices = alloc::vec![];
+
+    for bus in 0..=255 {
+        for device in 0..32 {
+            if let Some(device_info) = check_device(bus, device) {
+                let vendor = device_info.device_id.vendor;
+                let id = device_info.device_id.id;
+                use Vendor::*;
+                let (dev_type, dev_name) = match (vendor, id) {
+                    (VirtIO, 4176) => ("GPUs", "VirtIO PCI GPU"),
+                    (CirrusLogic, 184) => ("GPUs", "Cirrus SVGA"), //GD 5446?
+                    (_, _) => ("Unidentified PCI", "UNKNOWN DEVICE"),
+                };
+
+                let mut dev = xml::XMLElement::new(dev_name);
+                let mut pci_info = xml::XMLElement::new("PCI Info");
+                pci_info.set_attribute("id", id);
+                pci_info.set_attribute("device", device_info.device);
+                pci_info.set_attribute("vendor", vendor);
+                pci_info.set_attribute("class", device_info.full_class.to_string());
+                dev.set_child(pci_info);
+                devices.push((dev_type, dev));
+            }
+        }
+    }
+    for (dev_type, dev) in devices {
+        if let Some(abc) = dt.devices.get_mut(dev_type) {
+            abc.push(dev);
+        }
+    }
+}
+
+pub fn check_device(bus: u8, device: u8) -> Option<PciDeviceInfo> {
+    assert!(device < 32);
+    let (device_id, vendor_id) = get_ids(bus, device, 0);
+    if vendor_id == 0xFFFF {
+        // Device doesn't exist
+        return None;
+    }
+
+    let reg2 = unsafe { pci_config_read(bus, device, 0, 0x8) };
+    let class = ((reg2 >> 16) & 0x0000FFFF) as u16;
+    let pci_class = PciFullClass::from_u16(class);
+    let header_type = get_header_type(bus, device, 0);
+
+    Some(PciDeviceInfo {
+        header_type,
+        device,
+        bus,
+        device_id: DeviceID {
+            vendor: vendor_id.into(),
+            id:     device_id,
+        },
+        full_class: pci_class,
+        rev_id: (reg2 & 0x000000FF) as u8,
+    })
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct DeviceID {
+    pub vendor: Vendor,
+    pub id:     u16,
+}
+impl DeviceID {
+    pub const fn new(vendor: Vendor, id: u16) -> Self {
+        Self { vendor, id }
+    }
+}
+
+#[derive(PartialEq, Debug, Copy, Clone, Eq)]
+#[repr(u16)]
+pub enum Vendor {
+    ThreeDfxInteractiveInc = 0x121A,
+    ThreeDLabs = 0x3D3D,
+    AllianceSemiconductorCorp = 0x1142,
+    ARKLogicInc = 0xEDD8,
+    ATITechnologiesInc = 0x1002,
+    AvanceLogicIncALI = 0x1005,
+    ChipsandTechnologies = 0x102C,
+    CirrusLogic = 0x1013,
+    Compaq = 0x0E11,
+    CyrixCorp = 0x1078,
+    DiamondMultimediaSystems = 0x1092,
+    DigitalEquipmentCorp = 0x1011,
+    Iit = 0x1061,
+    IntegratedMicroSolutionsInc = 0x10E0,
+    IntelCorp = 0x8086,
+    IntergraphicsSystems = 0x10EA,
+    MacronixInc = 0x10D9,
+    MatroxGraphicsInc = 0x102B,
+    MiroComputersProductsAG = 0x1031,
+    NationalSemiconductorCorp = 0x100B,
+    NeoMagicCorp = 0x10C8,
+    Number9ComputerCompany = 0x105D,
+    NVidiaCorporation = 0x10DE,
+    NVidiaSgsthomson = 0x12D2,
+    OakTechnologyInc = 0x104E,
+    Qemu = 0x1234,
+    QuantumDesignsHKLtd = 0x1098,
+    Real3D = 0x003D,
+    Rendition = 0x1163,
+    S3Inc = 0x5333,
+    SierraSemiconductor = 0x10A8,
+    SiliconIntegratedSystemsSiS = 0x1039,
+    SiliconMotionInc = 0x126F,
+    STBSystemsInc = 0x10B4,
+    TexasInstruments = 0x104C,
+    ToshibaAmericaInfoSystems = 0x1179,
+    TridentMicrosystems = 0x1023,
+    TsengLabsInc = 0x100C,
+    TundraSemiconductorCorp = 0x10E3,
+    VIATechnologiesInc = 0x1106,
+    VirtIO = 0x1AF4,
+    VMWareInc = 0x15AD,
+    Weitek = 0x100E,
+    Unknown(u16),
+}
+
+impl From<u16> for Vendor {
+    fn from(vendor_id: u16) -> Self {
+        use Vendor::*;
+        match vendor_id {
+            0x121A => ThreeDfxInteractiveInc,
+            0x3D3D => ThreeDLabs,
+            0x1142 => AllianceSemiconductorCorp,
+            0xEDD8 => ARKLogicInc,
+            0x1002 => ATITechnologiesInc,
+            0x1005 => AvanceLogicIncALI,
+            0x102C => ChipsandTechnologies,
+            0x1013 => CirrusLogic,
+            0x0E11 => Compaq,
+            0x1078 => CyrixCorp,
+            0x1092 => DiamondMultimediaSystems,
+            0x1011 => DigitalEquipmentCorp,
+            0x1061 => Iit,
+            0x10E0 => IntegratedMicroSolutionsInc,
+            0x8086 => IntelCorp,
+            0x10EA => IntergraphicsSystems,
+            0x10D9 => MacronixInc,
+            0x102B => MatroxGraphicsInc,
+            0x1031 => MiroComputersProductsAG,
+            0x100B => NationalSemiconductorCorp,
+            0x10C8 => NeoMagicCorp,
+            0x105D => Number9ComputerCompany,
+            0x10DE => NVidiaCorporation,
+            0x12D2 => NVidiaSgsthomson,
+            0x104E => OakTechnologyInc,
+            0x1234 => Qemu,
+            0x1098 => QuantumDesignsHKLtd,
+            0x003D => Real3D,
+            0x1163 => Rendition,
+            0x5333 => S3Inc,
+            0x10A8 => SierraSemiconductor,
+            0x1039 => SiliconIntegratedSystemsSiS,
+            0x126F => SiliconMotionInc,
+            0x10B4 => STBSystemsInc,
+            0x104C => TexasInstruments,
+            0x1179 => ToshibaAmericaInfoSystems,
+            0x1023 => TridentMicrosystems,
+            0x100C => TsengLabsInc,
+            0x10E3 => TundraSemiconductorCorp,
+            0x1106 => VIATechnologiesInc,
+            0x1AF4 => VirtIO,
+            0x15AD => VMWareInc,
+            0x100E => Weitek,
+            id => Unknown(id),
+        }
+    }
+}
+
+impl Into<u16> for Vendor {
+    fn into(self) -> u16 {
+        use Vendor::*;
+        match self {
+            ThreeDfxInteractiveInc => 0x121A,
+            ThreeDLabs => 0x3D3D,
+            AllianceSemiconductorCorp => 0x1142,
+            ARKLogicInc => 0xEDD8,
+            ATITechnologiesInc => 0x1002,
+            AvanceLogicIncALI => 0x1005,
+            ChipsandTechnologies => 0x102C,
+            CirrusLogic => 0x1013,
+            Compaq => 0x0E11,
+            CyrixCorp => 0x1078,
+            DiamondMultimediaSystems => 0x1092,
+            DigitalEquipmentCorp => 0x1011,
+            Iit => 0x1061,
+            IntegratedMicroSolutionsInc => 0x10E0,
+            IntelCorp => 0x8086,
+            IntergraphicsSystems => 0x10EA,
+            MacronixInc => 0x10D9,
+            MatroxGraphicsInc => 0x102B,
+            MiroComputersProductsAG => 0x1031,
+            NationalSemiconductorCorp => 0x100B,
+            NeoMagicCorp => 0x10C8,
+            Number9ComputerCompany => 0x105D,
+            NVidiaCorporation => 0x10DE,
+            NVidiaSgsthomson => 0x12D2,
+            OakTechnologyInc => 0x104E,
+            Qemu => 0x1234,
+            QuantumDesignsHKLtd => 0x1098,
+            Real3D => 0x003D,
+            Rendition => 0x1163,
+            S3Inc => 0x5333,
+            SierraSemiconductor => 0x10A8,
+            SiliconIntegratedSystemsSiS => 0x1039,
+            SiliconMotionInc => 0x126F,
+            STBSystemsInc => 0x10B4,
+            TexasInstruments => 0x104C,
+            ToshibaAmericaInfoSystems => 0x1179,
+            TridentMicrosystems => 0x1023,
+            TsengLabsInc => 0x100C,
+            TundraSemiconductorCorp => 0x10E3,
+            VIATechnologiesInc => 0x1106,
+            VirtIO => 0x1AF4,
+            VMWareInc => 0x15AD,
+            Weitek => 0x100E,
+            Unknown(id) => id,
+        }
+    }
+}
+
+impl core::fmt::Display for Vendor {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        use Vendor::*;
+
+        match self {
+            Qemu => write!(f, "QEMU (0x1234)"),
+            VirtIO => write!(f, "VirtIO (0x1AF4)"),
+            VMWareInc => write!(f, "VMWARE (0x15AD)"),
+            S3Inc => write!(f, "S3 Incorporated (0x5333)"),
+            IntelCorp => write!(f, "Intel Corp. (0x8086)"),
+            ATITechnologiesInc => write!(f, "ATI (0x1002)"),
+            Unknown(id) => write!(f, "Unknown ({:#6})", id),
+            other => write!(f, "{other:?}"),
+        }?;
+
+        Ok(())
+    }
+}
+
+use core::fmt::Display;
+
+use crate::kmain::DEVICE_TREE;
+
+use {alloc::fmt::format, x86_64::instructions::port::Port};
+
+#[allow(non_camel_case_types, dead_code)]
+#[derive(Debug, Clone, Copy, PartialEq)]
+#[repr(C)]
+/// Class specification for a PCI device
+pub enum PciClass {
+    Unclassified = 0x00,
+    MassStorage = 0x01,
+    Network = 0x02,
+    Display = 0x03,
+    Multimedia = 0x04,
+    Memory = 0x05,
+    Bridge = 0x06,
+    Unknown = 0xFF,
+}
+
+impl From<u8> for PciClass {
+    /// Convert a u8 into the corresponding PciClass
+    fn from(n: u8) -> Self {
+        use PciClass::*;
+        match n {
+            0x00 => Unclassified,
+            0x01 => MassStorage,
+            0x02 => Network,
+            0x03 => Display,
+            0x04 => Multimedia,
+            0x05 => Memory,
+            0x06 => Bridge,
+            _ => Unknown,
+        }
+    }
+}
+
+#[allow(non_camel_case_types, dead_code)]
+#[derive(Debug, Clone, Copy, PartialEq)]
+#[repr(C)]
+/// Full class specification (type and subtype) for a PCI device.
+///
+/// Uses non-camel-case types for readability.
+pub enum PciFullClass {
+    Unclassified_NonVgaCompatible = 0x0000,
+    Unclassified_VgaCompatible = 0x0001,
+
+    MassStorage_ScsiBus = 0x0100,
+    MassStorage_IDE = 0x0101,
+    MassStorage_Floppy = 0x0102,
+    MassStorage_IpiBus = 0x0103,
+    MassStorage_RAID = 0x0104,
+    MassStorage_ATA = 0x0105,
+    MassStorage_SATA = 0x0106,
+    MassStorage_SerialSCSI = 0x0107,
+    MassStorage_NVM = 0x0108,
+    MassStorage_Other = 0x0180,
+
+    Network_Ethernet = 0x0200,
+    Network_TokenRing = 0x0201,
+    Network_FDDI = 0x0202,
+    Network_ATM = 0x0203,
+    Network_ISDN = 0x0204,
+    Network_WorldFlip = 0x0205,
+    Network_PICMG = 0x0206,
+    Network_Infiniband = 0x0207,
+    Network_Fabric = 0x0208,
+    Network_Other = 0x0280,
+
+    Display_VGA = 0x0300,
+    Display_XGA = 0x0301,
+    Display_3D = 0x0302,
+    Display_Other = 0x0380,
+
+    Multimedia_Video = 0x0400,
+    Multimedia_AudioController = 0x0401,
+    Multimedia_Telephony = 0x0402,
+    Multimedia_AudioDevice = 0x0403,
+    Multimedia_Other = 0x0480,
+
+    Memory_RAM = 0x0500,
+    Memory_Flash = 0x0501,
+    Memory_Other = 0x0580,
+
+    Bridge_Host = 0x0600,
+    Bridge_ISA = 0x0601,
+    Bridge_EISA = 0x0602,
+    Bridge_MCA = 0x0603,
+    Bridge_PciToPci = 0x0604,
+    Bridge_PCMCIA = 0x0605,
+    Bridge_NuBus = 0x0606,
+    Bridge_CardBus = 0x0607,
+    Bridge_RACEway = 0x0608,
+    Bridge_PciToPciSemiTransparent = 0x0609,
+    Bridge_InfinibandToPci = 0x060A,
+    Bridge_Other = 0x0680,
+
+    Unknown = 0xFFFF,
+}
+
+impl PciFullClass {
+    // listen, i know this sucks, but i didn't want to include
+    // `num`, `num-traits` and `num-derive` as dependencies for
+    // this crate just for a convenience function
+    /// Convert a u16 into the corresponding PciFullClass
+    pub fn from_u16(n: u16) -> PciFullClass {
+        match n {
+            0x0000 => PciFullClass::Unclassified_NonVgaCompatible,
+            0x0001 => PciFullClass::Unclassified_VgaCompatible,
+
+            0x0100 => PciFullClass::MassStorage_ScsiBus,
+            0x0101 => PciFullClass::MassStorage_IDE,
+            0x0102 => PciFullClass::MassStorage_Floppy,
+            0x0103 => PciFullClass::MassStorage_IpiBus,
+            0x0104 => PciFullClass::MassStorage_RAID,
+            0x0105 => PciFullClass::MassStorage_ATA,
+            0x0106 => PciFullClass::MassStorage_SATA,
+            0x0107 => PciFullClass::MassStorage_SerialSCSI,
+            0x0108 => PciFullClass::MassStorage_NVM,
+            0x0180 => PciFullClass::MassStorage_Other,
+
+            0x0200 => PciFullClass::Network_Ethernet,
+            0x0201 => PciFullClass::Network_TokenRing,
+            0x0202 => PciFullClass::Network_FDDI,
+            0x0203 => PciFullClass::Network_ATM,
+            0x0204 => PciFullClass::Network_ISDN,
+            0x0205 => PciFullClass::Network_WorldFlip,
+            0x0206 => PciFullClass::Network_PICMG,
+            0x0207 => PciFullClass::Network_Infiniband,
+            0x0208 => PciFullClass::Network_Fabric,
+            0x0280 => PciFullClass::Network_Other,
+
+            0x0300 => PciFullClass::Display_VGA,
+            0x0301 => PciFullClass::Display_XGA,
+            0x0302 => PciFullClass::Display_3D,
+            0x0380 => PciFullClass::Display_Other,
+
+            0x0400 => PciFullClass::Multimedia_Video,
+            0x0401 => PciFullClass::Multimedia_AudioController,
+            0x0402 => PciFullClass::Multimedia_Telephony,
+            0x0403 => PciFullClass::Multimedia_AudioDevice,
+            0x0480 => PciFullClass::Multimedia_Other,
+
+            0x0500 => PciFullClass::Memory_RAM,
+            0x0501 => PciFullClass::Memory_Flash,
+            0x0580 => PciFullClass::Memory_Other,
+
+            0x0600 => PciFullClass::Bridge_Host,
+            0x0601 => PciFullClass::Bridge_ISA,
+            0x0602 => PciFullClass::Bridge_EISA,
+            0x0603 => PciFullClass::Bridge_MCA,
+            0x0604 => PciFullClass::Bridge_PciToPci,
+            0x0605 => PciFullClass::Bridge_PCMCIA,
+            0x0606 => PciFullClass::Bridge_NuBus,
+            0x0607 => PciFullClass::Bridge_CardBus,
+            0x0608 => PciFullClass::Bridge_RACEway,
+            0x0609 => PciFullClass::Bridge_PciToPciSemiTransparent,
+            0x060A => PciFullClass::Bridge_InfinibandToPci,
+            0x0680 => PciFullClass::Bridge_Other,
+
+            _ => PciFullClass::Unknown,
+        }
+    }
+
+    /// Convert a PciFullClass to its u16 representation
+    pub fn as_u16(&self) -> u16 {
+        *self as u16
+    }
+}
+
+impl From<u16> for PciFullClass {
+    /// Convert a u16 into the corresponding PciFullClass
+    fn from(n: u16) -> Self {
+        Self::from_u16(n)
+    }
+}
+
+impl Display for PciFullClass {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(f, "{:?} ({:#06X})", self, self.as_u16())?;
+
+        Ok(())
+    }
+}
+
+unsafe fn pci_config_read(bus: u8, device: u8, func: u8, offset: u8) -> u32 {
+    let bus = bus as u32;
+    let device = device as u32;
+    let func = func as u32;
+    let offset = offset as u32;
+    // construct address param
+    let address =
+        ((bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x80000000) as u32;
+
+    // write address
+    Port::new(0xCF8).write(address);
+
+    // read data
+    Port::new(0xCFC).read()
+}
+
+unsafe fn pci_config_write(bus: u8, device: u8, func: u8, offset: u8, value: u32) {
+    let bus = bus as u32;
+    let device = device as u32;
+    let func = func as u32;
+    let offset = offset as u32;
+    // construct address param
+    let address =
+        ((bus << 16) | (device << 11) | (func << 8) | (offset & 0xFC) | 0x80000000) as u32;
+
+    // write address
+    Port::new(0xCF8).write(address);
+
+    // write data
+    Port::new(0xCFC).write(value);
+}
+
+fn get_header_type(bus: u8, device: u8, function: u8) -> u8 {
+    assert!(device < 32);
+    assert!(function < 8);
+    let res = unsafe { pci_config_read(bus, device, function, 0x0C) };
+    ((res >> 16) & 0xFF) as u8
+}
+
+fn get_ids(bus: u8, device: u8, function: u8) -> (u16, u16) {
+    assert!(device < 32);
+    assert!(function < 8);
+    let res = unsafe { pci_config_read(bus, device, function, 0) };
+    let dev_id = ((res >> 16) & 0xFFFF) as u16;
+    let vnd_id = (res & 0xFFFF) as u16;
+    (dev_id, vnd_id)
+}
diff --git a/kernel/src/arch/x86_64/virtio/mod.rs b/kernel/src/arch/x86_64/virtio/mod.rs
new file mode 100644
index 0000000..4af981d
--- /dev/null
+++ b/kernel/src/arch/x86_64/virtio/mod.rs
@@ -0,0 +1,38 @@
+use {
+    alloc::alloc::{alloc_zeroed, dealloc, handle_alloc_error},
+    core::{alloc::Layout, ptr::NonNull},
+    virtio_drivers::{BufferDirection, Hal, PhysAddr, PAGE_SIZE},
+};
+
+pub fn test() {
+    let ps = virtio_drivers::PAGE_SIZE;
+}
+
+pub struct AbleosHal;
+
+unsafe impl Hal for AbleosHal {
+    fn dma_alloc(pages: usize, _direction: BufferDirection) -> (PhysAddr, NonNull<u8>) {
+        todo!();
+    }
+
+    unsafe fn dma_dealloc(_paddr: PhysAddr, vaddr: NonNull<u8>, pages: usize) -> i32 {
+        todo!()
+    }
+
+    unsafe fn mmio_phys_to_virt(paddr: PhysAddr, _size: usize) -> NonNull<u8> {
+        NonNull::new(paddr as _).unwrap()
+    }
+
+    unsafe fn share(buffer: NonNull<[u8]>, _direction: BufferDirection) -> PhysAddr {
+        todo!()
+    }
+
+    unsafe fn unshare(_paddr: PhysAddr, _buffer: NonNull<[u8]>, _direction: BufferDirection) {
+        // Nothing to do, as the host already has access to all memory and we didn't copy the buffer
+        // anywhere else.
+        todo!()
+    }
+}
+fn virt_to_phys(vaddr: usize) -> PhysAddr {
+    vaddr
+}
diff --git a/kernel/src/device_tree.rs b/kernel/src/device_tree.rs
new file mode 100644
index 0000000..62c01f8
--- /dev/null
+++ b/kernel/src/device_tree.rs
@@ -0,0 +1,71 @@
+use alloc::{string::String, vec::Vec};
+
+use {crate::alloc::string::ToString, core::fmt, hashbrown::HashMap, xml::XMLElement};
+pub type Device = xml::XMLElement;
+
+#[derive(Debug)]
+pub struct DeviceTree {
+    pub devices: HashMap<String, Vec<Device>>,
+}
+impl DeviceTree {
+    pub fn new() -> Self {
+        let mut dt = Self {
+            devices: HashMap::new(),
+        };
+
+        // Human input devices
+        {
+            dt.devices.insert("Mice".to_string(), Vec::new());
+            dt.devices.insert("Keyboards".to_string(), Vec::new());
+            dt.devices.insert("Controllers".to_string(), Vec::new());
+            // Human Input Devices that do not fit into other catagories go in this spot
+            dt.devices.insert("Generic HIDs".to_string(), Vec::new());
+        }
+
+        {
+            dt.devices.insert("Disk Drives".to_string(), Vec::new());
+            dt.devices.insert("CD Drives".to_string(), Vec::new());
+        }
+
+        dt.devices.insert("Batteries".to_string(), Vec::new());
+        dt.devices.insert("Monitors".to_string(), Vec::new());
+        dt.devices.insert("GPUs".to_string(), Vec::new());
+        dt.devices.insert("CPUs".to_string(), Vec::new());
+
+        dt.devices.insert("USB".to_string(), Vec::new());
+        dt.devices.insert("Serial Ports".to_string(), Vec::new());
+        dt.devices.insert("Cameras".to_string(), Vec::new());
+        dt.devices
+            .insert("Biometric Devices".to_string(), Vec::new());
+
+        dt
+    }
+}
+use crate::utils::TAB;
+
+impl fmt::Display for DeviceTree {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        for (device_type, devices) in &self.devices {
+            writeln!(f, "\r{TAB}{}/\r", device_type)?;
+            for device in devices {
+                writeln!(f, "{TAB}{TAB}{}/\r", device.name)?;
+                for attr in &device.attributes {
+                    writeln!(f, "{TAB}{TAB}{TAB}{}\r", attr)?;
+                }
+                for child in &device.children {
+                    writeln!(f, "{TAB}{TAB}{TAB}{}\r", child.name)?;
+                    for attr in &child.attributes {
+                        writeln!(f, "{TAB}{TAB}{TAB}{TAB}{}\r", attr)?;
+                    }
+                    for child in &child.children {
+                        writeln!(f, "{TAB}{TAB}{TAB}{TAB}{}\r", child.name)?;
+                        for attr in &child.attributes {
+                            writeln!(f, "{TAB}{TAB}{TAB}{TAB}{TAB}{}\r", attr)?;
+                        }
+                    }
+                }
+            }
+        }
+        Ok(())
+    }
+}
diff --git a/kernel/src/interp/mod.rs b/kernel/src/interp/mod.rs
index 550cd0b..97e7cb5 100644
--- a/kernel/src/interp/mod.rs
+++ b/kernel/src/interp/mod.rs
@@ -18,9 +18,9 @@ use alloc::vec;
 #[derive(Debug)]
 
 pub struct WasmContext {
-    pub proc_id: Option<u64>,
+    pub proc_id:  Option<u64>,
     pub instance: Instance,
-    pub store: Store<HostState>,
+    pub store:    Store<HostState>,
 }
 
 pub fn wasm() -> Result<(), wasmi::Error> {
diff --git a/kernel/src/kmain.rs b/kernel/src/kmain.rs
index 19388f4..eb54979 100644
--- a/kernel/src/kmain.rs
+++ b/kernel/src/kmain.rs
@@ -2,14 +2,13 @@
 
 // use std::collections::HashMap;
 
-use alloc::vec::Vec;
-use log::{info, trace};
-use spin::{Lazy, Mutex};
+use {
+    alloc::vec::Vec,
+    log::{info, trace},
+    spin::{Lazy, Mutex},
+};
 
-use crate::arch::{hardware_random_u64, sloop};
-use crate::handle::Handle;
-use crate::schedule::Scheduler;
-use crate::{interp, task};
+use crate::{arch, device_tree::DeviceTree, schedule::Scheduler};
 
 use crate::alloc::string::ToString;
 
@@ -23,13 +22,13 @@ pub fn kmain(cmdline: &str, bootstrap: Option<&'static [u8]>) -> ! {
     let kcmd = clparse::Arguments::parse(cmdline.to_string()).unwrap();
     log::info!("Cmdline: {kcmd:?}");
 
-    // if kcmd.arguments.get("baka") == Some(&"true".to_string()) {
-    //     let _ = crate::arch::log(format_args!(include_str!("../data/⑨. バカ")));
-    // }
+    if kcmd.arguments.get("baka") == Some(&"true".to_string()) {
+        let _ = crate::arch::log(format_args!(include_str!("../data/⑨. バカ")));
+    }
 
-    // if kcmd.arguments.get("foobles") == Some(&"true".to_string()) {
-    //     let _ = crate::arch::log(format_args!("foobles\n"));
-    // }
+    if kcmd.arguments.get("foobles") == Some(&"true".to_string()) {
+        let _ = crate::arch::log(format_args!("foobles\n\r"));
+    }
 
     let bootstrap = bootstrap/*.expect("no bootstrap found")*/;
     match bootstrap {
@@ -38,24 +37,9 @@ pub fn kmain(cmdline: &str, bootstrap: Option<&'static [u8]>) -> ! {
             info!("No bootstrap module loaded.")
         }
     }
+    let mut dt = DEVICE_TREE.lock();
 
-    // use xml::XMLElement;
-    // let kcmd = XMLElement::new("cmdline");
-    // let hnd = Handle::new();
-    // kcmd.set_attribute("")
-    // OBJECTS.lock().insert(hnd, kcmd);
-
-    let abc = interp::wasm();
-
-    trace!("{:?}", abc);
-
-    // let sch = SCHEDULER;
-    // let mut sch = sch.lock();
-    // let wc = interp::build_wasm_context(alloc::vec::Vec::new()).unwrap();
-    // sch.schedule(wc, crate::schedule::ContextWake::None);
-
-    // sch.run();
-
+    info!("Device Tree {}", &dt);
     crate::arch::sloop()
 }
 
@@ -63,3 +47,8 @@ pub const SCHEDULER: Lazy<Mutex<Scheduler>> = Lazy::new(|| {
     let mut sch = Scheduler::new();
     Mutex::new(sch)
 });
+
+pub static DEVICE_TREE: Lazy<Mutex<DeviceTree>> = Lazy::new(|| {
+    let mut dt = DeviceTree::new();
+    Mutex::new(dt)
+});
diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs
index c2e1808..3068586 100644
--- a/kernel/src/lib.rs
+++ b/kernel/src/lib.rs
@@ -16,6 +16,7 @@ extern crate alloc;
 
 mod allocator;
 mod arch;
+pub mod device_tree;
 pub mod handle;
 pub mod interp;
 mod kmain;
@@ -23,6 +24,7 @@ mod logger;
 mod memory;
 mod schedule;
 mod task;
+pub mod utils;
 
 use versioning::Version;
 
diff --git a/kernel/src/utils.rs b/kernel/src/utils.rs
new file mode 100644
index 0000000..5477d28
--- /dev/null
+++ b/kernel/src/utils.rs
@@ -0,0 +1 @@
+pub const TAB: &str = "  ";
diff --git a/repbuild/limine.cfg b/repbuild/limine.cfg
index 8afc3c6..149bd06 100644
--- a/repbuild/limine.cfg
+++ b/repbuild/limine.cfg
@@ -2,7 +2,7 @@ ${ABLEOS_KERNEL}=boot:///kernel
 # TODO: Make a boot background image for ableOS
 
 DEFAULT_ENTRY=1
-TIMEOUT=50
+TIMEOUT=0
 VERBOSE=yes
 INTERFACE_RESOLUTION=1024x768
 # Terminal related settings
diff --git a/repbuild/src/main.rs b/repbuild/src/main.rs
index 9ddc68e..3242f3f 100644
--- a/repbuild/src/main.rs
+++ b/repbuild/src/main.rs
@@ -1,6 +1,8 @@
-use error_stack::{bail, report, Context, IntoReport, Result, ResultExt};
-use fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek};
-use std::{fmt::Display, fs::File, io, path::Path, process::Command};
+use {
+    error_stack::{bail, report, Context, IntoReport, Result, ResultExt},
+    fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
+    std::{fmt::Display, fs::File, io, path::Path, process::Command},
+};
 
 fn main() -> Result<(), Error> {
     env_logger::init();
@@ -153,19 +155,32 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
     if target == Target::X86_64 {
         #[rustfmt::skip]
         com.args([
+
+     
+
+
             "-bios",
                 std::env::var("REPBUILD_QEMU_FIRMWARE_PATH")
                 .as_deref()
                 .unwrap_or("/usr/share/ovmf/x64/OVMF_CODE.fd"),
             "-drive", "file=target/disk.img,format=raw",
             "-m", "4G",
-            "-serial", "stdio",
-            "-smp", "cores=2",
+            // "-serial", "stdio",
+            "-smp", "cores=4",
+            "-vga", "cirrus",
+            "-device", "virtio-gpu-pci",
+
+	        "-device", "virtio-serial,id=virtio-serial0",
+		    "-chardev", "stdio,id=char0,mux=on",
+            "-device", "virtconsole,chardev=char0",
+            "-device", "virtio-mouse-pci",
+
+            // "-device", "ati-vga", "model=rage128p"
         ]);
 
         #[cfg(target_os = "linux")]
         {
-            com.args(["-enable-kvm", "-cpu", "host"]);
+            // com.args(["-enable-kvm", "-cpu", "host"]);
         }
     }