diff --git a/src/driver/acpi/hpet.rs b/src/driver/acpi/hpet.rs
index 5dbf8a050881589bb6605f8307b8e4af1eb75c68..79381ef92988919c8c705c8054218f9bd7f4dbb6 100644
--- a/src/driver/acpi/hpet.rs
+++ b/src/driver/acpi/hpet.rs
@@ -10,7 +10,8 @@ use spin::{Lazy, Mutex};
 
 use crate::{
     debug, trace,
-    vfs::{FileDevice, IoResult},
+    util::slice_read::{self, slice_read, slice_write},
+    vfs::{FileDevice, IoError, IoResult},
 };
 
 use super::{rsdt::RSDT, SdtError};
@@ -234,12 +235,11 @@ impl FileDevice for HpetDevice {
 
     fn read(&self, offset: usize, buf: &mut [u8]) -> IoResult<usize> {
         let bytes = &HPET.lock().now_bytes()[..];
-        bytes.read(offset, buf)
+        slice_read(bytes, offset, buf)
     }
 
-    fn write(&mut self, offset: usize, buf: &[u8]) -> IoResult<usize> {
-        let mut bytes = &HPET.lock().now_bytes()[..];
-        bytes.write(offset, buf)
+    fn write(&mut self, _: usize, _: &[u8]) -> IoResult<usize> {
+        Err(IoError::PermissionDenied)
     }
 }
 
diff --git a/src/driver/rtc.rs b/src/driver/rtc.rs
index 5bd0d562d79dcbe84255b3efaa3a50d31d60e4e2..becbb1a46b7767d5658c66fd0b6ed097ddf98389 100644
--- a/src/driver/rtc.rs
+++ b/src/driver/rtc.rs
@@ -1,6 +1,7 @@
 use crate::{
     debug, error,
-    vfs::{self, FileDevice},
+    util::slice_read::slice_read,
+    vfs::{self, FileDevice, IoError, IoResult},
 };
 use chrono::{DateTime, TimeZone, Utc};
 use core::{
@@ -110,14 +111,13 @@ impl FileDevice for RtcDevice {
         mem::size_of::<i64>()
     }
 
-    fn read(&self, offset: usize, buf: &mut [u8]) -> vfs::IoResult<usize> {
+    fn read(&self, offset: usize, buf: &mut [u8]) -> IoResult<usize> {
         let bytes = &RTC.now_bytes()[..];
-        bytes.read(offset, buf)
+        slice_read(bytes, offset, buf)
     }
 
-    fn write(&mut self, offset: usize, buf: &[u8]) -> vfs::IoResult<usize> {
-        let mut bytes = &RTC.now_bytes()[..];
-        bytes.write(offset, buf)
+    fn write(&mut self, _: usize, _: &[u8]) -> IoResult<usize> {
+        Err(IoError::PermissionDenied)
     }
 }
 
diff --git a/src/main.rs b/src/main.rs
index fd91494e5c7757770f1d6d9c95102ab164d9a8df..f5fa755137e3df4df4d672324e38f91479e8a1f3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -24,14 +24,15 @@
 use core::sync::atomic::{AtomicUsize, Ordering};
 
 use crate::{
-    arch::cpu::idt::Irq,
+    arch::{cpu::idt::Irq, int},
     driver::{
         acpi::{apic::ApicId, ioapic::IoApic},
-        rtc,
+        rtc::{self, RtcDevice, RTC},
     },
     scheduler::kshell::kshell,
     smp::CPU_COUNT,
     util::fmt::NumberPostfix,
+    vfs::FileDevice,
 };
 
 extern crate alloc;
diff --git a/src/mem/pmm.rs b/src/mem/pmm.rs
index c1125ac1d57042bf729dea1a9aa0aa785d17cf7f..3b90688e488c85ec487327c4c3dc4153712fc830 100755
--- a/src/mem/pmm.rs
+++ b/src/mem/pmm.rs
@@ -131,8 +131,6 @@ impl PageFrameAllocator {
         self.used
             .fetch_add(count as u64 * PAGE_SIZE, Ordering::SeqCst);
 
-        // trace!("allocating pages first={first_page} count={}", count);
-
         PageFrame { first: addr, count }
     }
 
diff --git a/src/mem/slab.rs b/src/mem/slab.rs
index 7620c48b520470544862b361a92744542332c3d4..6575917e90b9e1f4cab32fbd99b425be0fb68260 100644
--- a/src/mem/slab.rs
+++ b/src/mem/slab.rs
@@ -90,6 +90,7 @@ impl SlabAllocator {
     }
 
     pub fn alloc(&self, size: usize) -> VirtAddr {
+        // crate::println!("alloc {size}");
         if let Some(slab) = self.get_slab(size) {
             slab.write().alloc(&self.stats)
         } else {
diff --git a/src/scheduler/kshell/shell.rs b/src/scheduler/kshell/shell.rs
index 34f8360443185f0888cccb93a566e50527bf0da9..c72b36d1bd57adb2be0a0d0992c34fac53cd142c 100644
--- a/src/scheduler/kshell/shell.rs
+++ b/src/scheduler/kshell/shell.rs
@@ -1,6 +1,6 @@
 use crate::{
     driver::acpi::hpet::HPET,
-    mem::pmm::PageFrameAllocator,
+    mem::{from_higher_half, pmm::PageFrameAllocator},
     util::fmt::NumberPostfix,
     vfs::{
         self,
@@ -13,7 +13,8 @@ use alloc::{borrow::ToOwned, string::String, sync::Arc};
 use chrono::{TimeZone, Utc};
 use core::fmt::Write;
 use snafu::ResultExt;
-use spin::Mutex;
+use spin::{Mutex, MutexGuard};
+use x86_64::VirtAddr;
 
 use super::{term::Term, Error, IoSnafu, Result};
 
@@ -103,7 +104,7 @@ impl<'fbo> Shell<'fbo> {
     }
 
     fn splash_cmd(&mut self, _: Option<&str>) -> Result<()> {
-        _ = writeln!(self.term, "{KERNEL_SPLASH}");
+        // _ = writeln!(self.term, "{KERNEL_SPLASH}");
         _ = writeln!(self.term, "Welcome to {KERNEL_NAME} - {KERNEL_VERSION} (built {KERNEL_BUILD_TIME} build [{KERNEL_BUILD_REV}])");
         Ok(())
     }
@@ -156,14 +157,16 @@ impl<'fbo> Shell<'fbo> {
         let file = vfs::get_file(resource, false, false).with_context(|_| IoSnafu {
             resource: resource.to_owned(),
         })?;
-        let mut file = file.lock();
+        let file = file.lock();
 
         let mut at = 0usize;
         let mut buf = [0u8; 16];
         loop {
+            let addr = (&*file) as *const _ as *const () as u64;
             let read = file.read(at, &mut buf).with_context(|_| IoSnafu {
                 resource: resource.to_owned(),
             })?;
+
             if read == 0 {
                 break;
             }
diff --git a/src/util/slice_read.rs b/src/util/slice_read.rs
index 64bfaef1ce86600a2300151acd2b92d4a2e00898..37d8a5f712cc3ee1437e5798bf6b8acfde7ea53d 100644
--- a/src/util/slice_read.rs
+++ b/src/util/slice_read.rs
@@ -2,46 +2,26 @@ use crate::vfs::{FileDevice, IoError, IoResult};
 
 //
 
-impl FileDevice for &'_ [u8] {
-    fn len(&self) -> usize {
-        self.len()
-    }
+pub fn slice_read(this: &[u8], offset: usize, buf: &mut [u8]) -> IoResult<usize> {
+    let len = this
+        .len()
+        .checked_sub(offset)
+        .ok_or(IoError::UnexpectedEOF)?
+        .min(buf.len());
 
-    fn read(&self, offset: usize, buf: &mut [u8]) -> IoResult<usize> {
-        let len = self
-            .len()
-            .checked_sub(offset)
-            .ok_or(IoError::UnexpectedEOF)?
-            .min(buf.len());
+    buf[..len].copy_from_slice(&this[offset..offset + len]);
 
-        buf[..len].copy_from_slice(&self[offset..offset + len]);
-
-        Ok(len)
-    }
-
-    fn write(&mut self, offset: usize, buf: &[u8]) -> IoResult<usize> {
-        Err(IoError::PermissionDenied)
-    }
+    Ok(len)
 }
 
-impl FileDevice for &'_ mut [u8] {
-    fn len(&self) -> usize {
-        self.len()
-    }
-
-    fn read(&self, offset: usize, buf: &mut [u8]) -> IoResult<usize> {
-        self.as_ref().read(offset, buf)
-    }
-
-    fn write(&mut self, offset: usize, buf: &[u8]) -> IoResult<usize> {
-        let len = self
-            .len()
-            .checked_sub(offset)
-            .ok_or(IoError::UnexpectedEOF)?
-            .min(buf.len());
+pub fn slice_write(this: &mut [u8], offset: usize, buf: &[u8]) -> IoResult<usize> {
+    let len = this
+        .len()
+        .checked_sub(offset)
+        .ok_or(IoError::UnexpectedEOF)?
+        .min(buf.len());
 
-        self[offset..offset + len].copy_from_slice(&buf[..len]);
+    this[offset..offset + len].copy_from_slice(&buf[..len]);
 
-        Ok(len)
-    }
+    Ok(len)
 }
diff --git a/src/vfs/devices.rs b/src/vfs/devices.rs
index 7ea97988f3fd67cc107b419af2599fbc532f8c8e..5fb464e986f0971c075b10469a531bda309cf4f0 100644
--- a/src/vfs/devices.rs
+++ b/src/vfs/devices.rs
@@ -3,9 +3,11 @@ use crate::{
     vfs,
 };
 
+use super::Node;
+
 //
 
-pub fn install() {
-    vfs::install_dev("/dev/rtc", RtcDevice);
-    vfs::install_dev("/dev/hpet", HpetDevice);
+pub fn install(root: Node) {
+    vfs::install_dev_with(root.clone(), "/dev/rtc", RtcDevice);
+    vfs::install_dev_with(root, "/dev/hpet", HpetDevice);
 }
diff --git a/src/vfs/mod.rs b/src/vfs/mod.rs
index 55b6a0ca633586dbd27ba6e1cd466cf90cd7ad91..1ec71e3ddd7122c6687a231b9ad9c78c7a37971c 100644
--- a/src/vfs/mod.rs
+++ b/src/vfs/mod.rs
@@ -21,65 +21,35 @@ pub mod path;
 static _ROOT_NODE: Lazy<Root> = Lazy::new(|| Directory::from(""));
 pub static ROOT: Lazy<Root> = Lazy::new(|| {
     debug!("Initializing VFS");
-    devices::install();
+    devices::install(Node::Directory(_ROOT_NODE.clone()));
     _ROOT_NODE.clone()
 });
 
 //
 
-pub fn get_node(path: impl AsRef<Path>, make_dirs: bool) -> IoResult<Node> {
-    let mut node = Node::Directory(ROOT.clone());
-
-    for part in path.as_ref().iter() {
-        match node {
-            Node::File(_) => return Err(IoError::NotADirectory),
-            Node::Directory(_dir) => {
-                let mut dir = _dir.lock();
-                // TODO: only Node::Directory should be cloned
-
-                node = if let Ok(node) = dir.get_node(part) {
-                    node
-                } else if make_dirs {
-                    let node = Node::Directory(Directory::from(part));
-                    dir.create_node(part, node.clone())?;
-                    node
-                } else {
-                    return Err(IoError::NotFound);
-                };
-            }
-        }
-    }
+pub fn get_root() -> Node {
+    Node::Directory(ROOT.clone())
+}
 
-    Ok(node)
+pub fn get_node(path: impl AsRef<Path>, make_dirs: bool) -> IoResult<Node> {
+    get_node_with(get_root(), path, make_dirs)
 }
 
 pub fn get_dir(path: impl AsRef<Path>, make_dirs: bool) -> IoResult<DirRef> {
-    let node = get_node(path, make_dirs)?;
-    match node {
-        Node::File(_) => Err(IoError::NotADirectory),
-        Node::Directory(dir) => Ok(dir),
-    }
+    get_dir_with(get_root(), path, make_dirs)
 }
 
 // TODO: create
-pub fn get_file(path: impl AsRef<Path>, make_dirs: bool, _create: bool) -> IoResult<FileRef> {
-    let node = get_node(path, make_dirs)?;
-    match node {
-        Node::File(file) => Ok(file),
-        Node::Directory(_) => Err(IoError::IsADirectory),
-    }
+pub fn get_file(path: impl AsRef<Path>, make_dirs: bool, create: bool) -> IoResult<FileRef> {
+    get_file_with(get_root(), path, make_dirs, create)
 }
 
 pub fn create_device(path: impl AsRef<Path>, make_dirs: bool, dev: FileRef) -> IoResult<()> {
-    create_node(path, make_dirs, Node::File(dev))
+    create_device_with(get_root(), path, make_dirs, dev)
 }
 
 pub fn install_dev(path: impl AsRef<Path>, dev: impl FileDevice + Send + Sync + 'static) {
-    let path = path.as_ref();
-    debug!("installing VFS device at {path:?}");
-    if let Err(err) = create_device(path, true, Arc::new(Mutex::new(dev)) as _) {
-        error!("failed to install VFS device at {path:?} : {err:?}");
-    }
+    install_dev_with(get_root(), path, dev)
 }
 
 pub use {get_dir as read_dir, get_file as open};
@@ -334,25 +304,20 @@ fn install_dev_with(
 }
 
 fn create_node_with(
-    node: Node,
+    root: Node,
     path: impl AsRef<Path>,
     make_dirs: bool,
     node: Node,
 ) -> IoResult<()> {
     let (parent_dir, file_name) = path.as_ref().split().ok_or(IoError::NotFound)?;
-    let parent_dir = get_dir(parent_dir, make_dirs)?;
+    let parent_dir = get_dir_with(root, parent_dir, make_dirs)?;
 
     let mut parent_dir = parent_dir.lock();
-    parent_dir.create_node_with(node, file_name, node)?;
+    parent_dir.create_node(file_name, node)?;
 
     Ok(())
 }
-fn create_node(path: impl AsRef<Path>, make_dirs: bool, node: Node) -> IoResult<()> {
-    let (parent_dir, file_name) = path.as_ref().split().ok_or(IoError::NotFound)?;
-    let parent_dir = get_dir(parent_dir, make_dirs)?;
 
-    let mut parent_dir = parent_dir.lock();
-    parent_dir.create_node(file_name, node)?;
-
-    Ok(())
+fn create_node(path: impl AsRef<Path>, make_dirs: bool, node: Node) -> IoResult<()> {
+    create_node_with(Node::Directory(ROOT.clone()), path, make_dirs, node)
 }