diff --git a/src/arch/aarch64/mod.rs b/src/arch/aarch64/mod.rs
index 1fd628951295cc3303b2fbffce1a9426ab6e58bb..0f353b390b2859e11c9e651d4c941c656db9365e 100644
--- a/src/arch/aarch64/mod.rs
+++ b/src/arch/aarch64/mod.rs
@@ -33,4 +33,6 @@ pub mod vectors;
 /// Early init support
 pub mod init;
 
+pub mod time;
+
 pub use ::rmm::AArch64Arch as CurrentRmmArch;
diff --git a/src/arch/aarch64/time.rs b/src/arch/aarch64/time.rs
new file mode 100644
index 0000000000000000000000000000000000000000..60809b40df4ad0ac6c280c03c095197c4f3fe9e4
--- /dev/null
+++ b/src/arch/aarch64/time.rs
@@ -0,0 +1,4 @@
+pub fn counter() -> u128 {
+    //TODO: aarch64 generic timer counter
+    0
+}
diff --git a/src/arch/x86/device/hpet.rs b/src/arch/x86/device/hpet.rs
index 1ab3ce9fc6e5048a35463644fc8e7b62992bf1f8..40d7d4e03a23e52c9726343fea9e5d37971449a4 100644
--- a/src/arch/x86/device/hpet.rs
+++ b/src/arch/x86/device/hpet.rs
@@ -1,22 +1,22 @@
 use crate::acpi::hpet::Hpet;
 
-static LEG_RT_CNF: u64 = 2;
-static ENABLE_CNF: u64 = 1;
-
-static TN_VAL_SET_CNF: u64 = 0x40;
-static TN_TYPE_CNF: u64 = 0x08;
-static TN_INT_ENB_CNF: u64 = 0x04;
-
-static CAPABILITY_OFFSET: usize = 0x00;
-static GENERAL_CONFIG_OFFSET: usize = 0x10;
-static GENERAL_INTERRUPT_OFFSET: usize = 0x20;
-static MAIN_COUNTER_OFFSET: usize = 0xF0;
-// static NUM_TIMER_CAP_MASK: u64 = 0x0f00;
-static LEG_RT_CAP: u64 = 0x8000;
-static T0_CONFIG_CAPABILITY_OFFSET: usize = 0x100;
-static T0_COMPARATOR_OFFSET: usize = 0x108;
-
-static PER_INT_CAP: u64 = 0x10;
+const LEG_RT_CNF: u64 = 2;
+const ENABLE_CNF: u64 = 1;
+
+const TN_VAL_SET_CNF: u64 = 0x40;
+const TN_TYPE_CNF: u64 = 0x08;
+const TN_INT_ENB_CNF: u64 = 0x04;
+
+pub(crate) const CAPABILITY_OFFSET: usize = 0x00;
+const GENERAL_CONFIG_OFFSET: usize = 0x10;
+const GENERAL_INTERRUPT_OFFSET: usize = 0x20;
+pub(crate) const MAIN_COUNTER_OFFSET: usize = 0xF0;
+// const NUM_TIMER_CAP_MASK: u64 = 0x0f00;
+const LEG_RT_CAP: u64 = 0x8000;
+const T0_CONFIG_CAPABILITY_OFFSET: usize = 0x100;
+const T0_COMPARATOR_OFFSET: usize = 0x108;
+
+const PER_INT_CAP: u64 = 0x10;
 
 pub unsafe fn init(hpet: &mut Hpet) -> bool {
     println!("HPET Before Init");
diff --git a/src/arch/x86/device/pit.rs b/src/arch/x86/device/pit.rs
index 7c96be162914d7e7d53041a8e0730d12e0bc61f5..fdf54a14b239c8008cff4a82301d6693e81ddb87 100644
--- a/src/arch/x86/device/pit.rs
+++ b/src/arch/x86/device/pit.rs
@@ -5,20 +5,24 @@ pub static mut CHAN1: Pio<u8> = Pio::new(0x41);
 pub static mut CHAN2: Pio<u8> = Pio::new(0x42);
 pub static mut COMMAND: Pio<u8> = Pio::new(0x43);
 
-static SELECT_CHAN0: u8 = 0;
-static LOHI: u8 = 0x30;
+const SELECT_CHAN0: u8 = 0b00 << 6;
+const ACCESS_LATCH: u8 = 0b00 << 4;
+const ACCESS_LOHI: u8 = 0b11 << 4;
+const MODE_2: u8 = 0b010 << 1;
 
-static CHAN0_DIVISOR: u16 = 2685;
+const CHAN0_DIVISOR: u16 = 2685;
 
 pub unsafe fn init() {
-    COMMAND.write(SELECT_CHAN0 | LOHI | 5);
-    CHAN0.write((CHAN0_DIVISOR & 0xFF) as u8);
+    COMMAND.write(SELECT_CHAN0 | ACCESS_LOHI | MODE_2);
+    CHAN0.write(CHAN0_DIVISOR as u8);
     CHAN0.write((CHAN0_DIVISOR >> 8) as u8);
 }
 
 pub unsafe fn read() -> u16 {
-    COMMAND.write(SELECT_CHAN0 | 0);
+    COMMAND.write(SELECT_CHAN0 | ACCESS_LATCH);
     let low = CHAN0.read();
     let high = CHAN0.read();
-    ((high as u16) << 8) | (low as u16)
+    let counter = ((high as u16) << 8) | (low as u16);
+    // Counter is inverted, subtract from CHAN0_DIVISOR
+    CHAN0_DIVISOR.saturating_sub(counter)
 }
diff --git a/src/arch/x86/mod.rs b/src/arch/x86/mod.rs
index df27301e91be13a0ab5080403ae29b93e0cd1292..4c294ef1b33e4c1fffae8b93a0b3e05658b40cec 100644
--- a/src/arch/x86/mod.rs
+++ b/src/arch/x86/mod.rs
@@ -40,6 +40,8 @@ pub mod start;
 /// Stop function
 pub mod stop;
 
+pub mod time;
+
 pub use ::rmm::X86Arch as CurrentRmmArch;
 
 // Flags
diff --git a/src/arch/x86/time.rs b/src/arch/x86/time.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ca1fa5ee838507687eb1cbfa7536bf89a7e79d05
--- /dev/null
+++ b/src/arch/x86/time.rs
@@ -0,0 +1,16 @@
+use crate::acpi::ACPI_TABLE;
+use super::device::{hpet, pit};
+
+pub fn counter() -> u128 {
+    if let Some(ref hpet) = *ACPI_TABLE.hpet.read() {
+        let capability = unsafe { hpet.base_address.read_u64(hpet::CAPABILITY_OFFSET) };
+        let period_fs = (capability >> 32) as u128;
+        let counter = unsafe { hpet.base_address.read_u64(hpet::MAIN_COUNTER_OFFSET) };
+        (counter as u128 * period_fs) / 1_000_000
+    } else {
+        // 1.193182 MHz PIT is approximately 838.095 nanoseconds
+        let period_ns = 838;
+        let counter = unsafe { pit::read() };
+        counter as u128 * period_ns
+    }
+}
diff --git a/src/arch/x86_64/device/hpet.rs b/src/arch/x86_64/device/hpet.rs
index 1ab3ce9fc6e5048a35463644fc8e7b62992bf1f8..40d7d4e03a23e52c9726343fea9e5d37971449a4 100644
--- a/src/arch/x86_64/device/hpet.rs
+++ b/src/arch/x86_64/device/hpet.rs
@@ -1,22 +1,22 @@
 use crate::acpi::hpet::Hpet;
 
-static LEG_RT_CNF: u64 = 2;
-static ENABLE_CNF: u64 = 1;
-
-static TN_VAL_SET_CNF: u64 = 0x40;
-static TN_TYPE_CNF: u64 = 0x08;
-static TN_INT_ENB_CNF: u64 = 0x04;
-
-static CAPABILITY_OFFSET: usize = 0x00;
-static GENERAL_CONFIG_OFFSET: usize = 0x10;
-static GENERAL_INTERRUPT_OFFSET: usize = 0x20;
-static MAIN_COUNTER_OFFSET: usize = 0xF0;
-// static NUM_TIMER_CAP_MASK: u64 = 0x0f00;
-static LEG_RT_CAP: u64 = 0x8000;
-static T0_CONFIG_CAPABILITY_OFFSET: usize = 0x100;
-static T0_COMPARATOR_OFFSET: usize = 0x108;
-
-static PER_INT_CAP: u64 = 0x10;
+const LEG_RT_CNF: u64 = 2;
+const ENABLE_CNF: u64 = 1;
+
+const TN_VAL_SET_CNF: u64 = 0x40;
+const TN_TYPE_CNF: u64 = 0x08;
+const TN_INT_ENB_CNF: u64 = 0x04;
+
+pub(crate) const CAPABILITY_OFFSET: usize = 0x00;
+const GENERAL_CONFIG_OFFSET: usize = 0x10;
+const GENERAL_INTERRUPT_OFFSET: usize = 0x20;
+pub(crate) const MAIN_COUNTER_OFFSET: usize = 0xF0;
+// const NUM_TIMER_CAP_MASK: u64 = 0x0f00;
+const LEG_RT_CAP: u64 = 0x8000;
+const T0_CONFIG_CAPABILITY_OFFSET: usize = 0x100;
+const T0_COMPARATOR_OFFSET: usize = 0x108;
+
+const PER_INT_CAP: u64 = 0x10;
 
 pub unsafe fn init(hpet: &mut Hpet) -> bool {
     println!("HPET Before Init");
diff --git a/src/arch/x86_64/device/pit.rs b/src/arch/x86_64/device/pit.rs
index 7c96be162914d7e7d53041a8e0730d12e0bc61f5..fdf54a14b239c8008cff4a82301d6693e81ddb87 100644
--- a/src/arch/x86_64/device/pit.rs
+++ b/src/arch/x86_64/device/pit.rs
@@ -5,20 +5,24 @@ pub static mut CHAN1: Pio<u8> = Pio::new(0x41);
 pub static mut CHAN2: Pio<u8> = Pio::new(0x42);
 pub static mut COMMAND: Pio<u8> = Pio::new(0x43);
 
-static SELECT_CHAN0: u8 = 0;
-static LOHI: u8 = 0x30;
+const SELECT_CHAN0: u8 = 0b00 << 6;
+const ACCESS_LATCH: u8 = 0b00 << 4;
+const ACCESS_LOHI: u8 = 0b11 << 4;
+const MODE_2: u8 = 0b010 << 1;
 
-static CHAN0_DIVISOR: u16 = 2685;
+const CHAN0_DIVISOR: u16 = 2685;
 
 pub unsafe fn init() {
-    COMMAND.write(SELECT_CHAN0 | LOHI | 5);
-    CHAN0.write((CHAN0_DIVISOR & 0xFF) as u8);
+    COMMAND.write(SELECT_CHAN0 | ACCESS_LOHI | MODE_2);
+    CHAN0.write(CHAN0_DIVISOR as u8);
     CHAN0.write((CHAN0_DIVISOR >> 8) as u8);
 }
 
 pub unsafe fn read() -> u16 {
-    COMMAND.write(SELECT_CHAN0 | 0);
+    COMMAND.write(SELECT_CHAN0 | ACCESS_LATCH);
     let low = CHAN0.read();
     let high = CHAN0.read();
-    ((high as u16) << 8) | (low as u16)
+    let counter = ((high as u16) << 8) | (low as u16);
+    // Counter is inverted, subtract from CHAN0_DIVISOR
+    CHAN0_DIVISOR.saturating_sub(counter)
 }
diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs
index 5dc0fd1a3c53b2466331b5bb7aec84d21f84bbc9..ca21bb516c759bfd4e758ca3c4920d23aad5159b 100644
--- a/src/arch/x86_64/mod.rs
+++ b/src/arch/x86_64/mod.rs
@@ -40,6 +40,8 @@ pub mod start;
 /// Stop function
 pub mod stop;
 
+pub mod time;
+
 pub use ::rmm::X8664Arch as CurrentRmmArch;
 
 // Flags
diff --git a/src/arch/x86_64/time.rs b/src/arch/x86_64/time.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ca1fa5ee838507687eb1cbfa7536bf89a7e79d05
--- /dev/null
+++ b/src/arch/x86_64/time.rs
@@ -0,0 +1,16 @@
+use crate::acpi::ACPI_TABLE;
+use super::device::{hpet, pit};
+
+pub fn counter() -> u128 {
+    if let Some(ref hpet) = *ACPI_TABLE.hpet.read() {
+        let capability = unsafe { hpet.base_address.read_u64(hpet::CAPABILITY_OFFSET) };
+        let period_fs = (capability >> 32) as u128;
+        let counter = unsafe { hpet.base_address.read_u64(hpet::MAIN_COUNTER_OFFSET) };
+        (counter as u128 * period_fs) / 1_000_000
+    } else {
+        // 1.193182 MHz PIT is approximately 838.095 nanoseconds
+        let period_ns = 838;
+        let counter = unsafe { pit::read() };
+        counter as u128 * period_ns
+    }
+}
diff --git a/src/time.rs b/src/time.rs
index 75717f2fc7748c069949916e4370dc909c7f585f..3d82c3903d22eb69b80dacf6c19de46327b58abf 100644
--- a/src/time.rs
+++ b/src/time.rs
@@ -8,7 +8,7 @@ pub static START: Mutex<u128> = Mutex::new(0);
 pub static OFFSET: Mutex<u128> = Mutex::new(0);
 
 pub fn monotonic() -> u128 {
-    *OFFSET.lock()
+    *OFFSET.lock() + crate::arch::time::counter()
 }
 
 pub fn realtime() -> u128 {