From 2052cc8cdc07b3dff5b73a6a00bcadb9d1ea0e1d Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Mon, 14 Nov 2022 11:12:44 -0700
Subject: [PATCH] Allow arch to provide higher precision time

---
 src/arch/aarch64/mod.rs        |  2 ++
 src/arch/aarch64/time.rs       |  4 ++++
 src/arch/x86/device/hpet.rs    | 34 +++++++++++++++++-----------------
 src/arch/x86/device/pit.rs     | 18 +++++++++++-------
 src/arch/x86/mod.rs            |  2 ++
 src/arch/x86/time.rs           | 16 ++++++++++++++++
 src/arch/x86_64/device/hpet.rs | 34 +++++++++++++++++-----------------
 src/arch/x86_64/device/pit.rs  | 18 +++++++++++-------
 src/arch/x86_64/mod.rs         |  2 ++
 src/arch/x86_64/time.rs        | 16 ++++++++++++++++
 src/time.rs                    |  2 +-
 11 files changed, 99 insertions(+), 49 deletions(-)
 create mode 100644 src/arch/aarch64/time.rs
 create mode 100644 src/arch/x86/time.rs
 create mode 100644 src/arch/x86_64/time.rs

diff --git a/src/arch/aarch64/mod.rs b/src/arch/aarch64/mod.rs
index 1fd62895..0f353b39 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 00000000..60809b40
--- /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 1ab3ce9f..40d7d4e0 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 7c96be16..fdf54a14 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 df27301e..4c294ef1 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 00000000..ca1fa5ee
--- /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 1ab3ce9f..40d7d4e0 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 7c96be16..fdf54a14 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 5dc0fd1a..ca21bb51 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 00000000..ca1fa5ee
--- /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 75717f2f..3d82c390 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 {
-- 
GitLab