use core::{cell::LazyCell, time::Duration};
static TIMER_FREQ: TimerFreq = TimerFreq(LazyCell::new(timer_freq));
struct TimerFreq(LazyCell<u64>);
unsafe impl Sync for TimerFreq {}
#[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub struct Instant(u64);
impl Instant {
#[must_use = "Has no effect if the result is unused"]
pub fn now() -> Self {
Self(1000 * 1000 * timer_tick() / *TIMER_FREQ.0)
}
#[must_use = "Has no effect if the result is unused"]
pub const fn zero() -> Self {
Self(0)
}
#[must_use = "Has no effect if the result is unused"]
pub const fn duration_since(&self, earlier: Self) -> Duration {
Duration::from_micros(self.0.saturating_sub(earlier.0))
}
#[must_use = "Has no effect if the result is unused"]
pub fn elapsed(&self) -> Duration {
Self::now().duration_since(*self)
}
}
#[must_use = "Has no effect if the result is unused"]
fn timer_tick() -> u64 {
unsafe {
#[cfg(target_arch = "x86")]
{
core::arch::x86::_rdtsc()
}
#[cfg(target_arch = "x86_64")]
{
core::arch::x86_64::_rdtsc()
}
#[cfg(target_arch = "aarch64")]
{
let mut ticks: u64;
core::arch::asm!("mrs {}, cntvct_el0", out(reg) ticks);
ticks
}
}
}
#[must_use = "Has no effect if the result is unused"]
fn timer_freq() -> u64 {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{
let start = timer_tick();
uefi::boot::stall(1000);
let end = timer_tick();
(end - start) * 1000
}
#[cfg(target_arch = "aarch64")]
unsafe {
let mut freq: u64;
core::arch::asm!("mrs {}, cntfrq_el0", out(reg) freq);
freq
}
}