From ba634ed68a6096443ae9b585f8abf0d19bebcd1a Mon Sep 17 00:00:00 2001 From: Alex Zenla Date: Mon, 3 Nov 2025 02:57:22 -0500 Subject: [PATCH] fix(platform/timer): on x86_64, elide usage of asm!() and use _rdtsc() intrinsic --- crates/sprout/src/platform/timer.rs | 4 +- crates/sprout/src/platform/timer/aarch64.rs | 10 ----- crates/sprout/src/platform/timer/x86_64.rs | 49 +++------------------ 3 files changed, 8 insertions(+), 55 deletions(-) diff --git a/crates/sprout/src/platform/timer.rs b/crates/sprout/src/platform/timer.rs index 9a8b743..55eb28a 100644 --- a/crates/sprout/src/platform/timer.rs +++ b/crates/sprout/src/platform/timer.rs @@ -17,7 +17,7 @@ pub enum TickFrequency { /// The platform provides the tick frequency. Hardware(u64), /// The tick frequency is measured internally. - Measured(u64, Duration), + Measured(u64), } impl TickFrequency { @@ -25,7 +25,7 @@ impl TickFrequency { fn ticks(&self) -> u64 { match self { TickFrequency::Hardware(frequency) => *frequency, - TickFrequency::Measured(frequency, _) => *frequency, + TickFrequency::Measured(frequency) => *frequency, } } diff --git a/crates/sprout/src/platform/timer/aarch64.rs b/crates/sprout/src/platform/timer/aarch64.rs index 153bd1b..1cd6fce 100644 --- a/crates/sprout/src/platform/timer/aarch64.rs +++ b/crates/sprout/src/platform/timer/aarch64.rs @@ -10,16 +10,6 @@ pub fn ticks() -> u64 { counter } -/// We can use the actual ticks value as our start value. -pub fn start() -> u64 { - ticks() -} - -/// We can use the actual ticks value as our stop value. -pub fn stop() -> u64 { - ticks() -} - /// Our frequency is provided by cntfrq_el0 on the platform. pub fn frequency() -> TickFrequency { let frequency: u64; diff --git a/crates/sprout/src/platform/timer/x86_64.rs b/crates/sprout/src/platform/timer/x86_64.rs index b47567b..add083a 100644 --- a/crates/sprout/src/platform/timer/x86_64.rs +++ b/crates/sprout/src/platform/timer/x86_64.rs @@ -1,5 +1,4 @@ use crate::platform::timer::TickFrequency; -use core::arch::asm; use core::time::Duration; /// We will measure the frequency of the timer based on 1000 microseconds. @@ -8,52 +7,16 @@ const MEASURE_FREQUENCY_DURATION: Duration = Duration::from_micros(1000); /// Read the number of ticks from the platform timer. pub fn ticks() -> u64 { - let mut eax: u32; - let mut edx: u32; - - unsafe { - asm!("rdtsc", out("eax") eax, out("edx") edx); - } - - (edx as u64) << 32 | eax as u64 -} - -/// Read the starting number of ticks from the platform timer. -pub fn start() -> u64 { - let rax: u64; - unsafe { - asm!( - "mfence", - "lfence", - "rdtsc", - "shl rdx, 32", - "or rax, rdx", - out("rax") rax - ); - } - rax -} - -/// Read the ending number of ticks from the platform timer. -pub fn stop() -> u64 { - let rax: u64; - unsafe { - asm!( - "rdtsc", - "lfence", - "shl rdx, 32", - "or rax, rdx", - out("rax") rax - ); - } - rax + // SAFETY: Reads the platform timer, which is safe in any context. + unsafe { core::arch::x86_64::_rdtsc() } } /// Measure the frequency of the platform timer. +/// NOTE: Intentionally, we do not synchronize rdtsc during measurement to match systemd behavior. fn measure_frequency() -> u64 { - let start = start(); + let start = ticks(); uefi::boot::stall(MEASURE_FREQUENCY_DURATION); - let stop = stop(); + let stop = ticks(); let elapsed = stop.wrapping_sub(start) as f64; (elapsed / MEASURE_FREQUENCY_DURATION.as_secs_f64()) as u64 } @@ -62,5 +25,5 @@ fn measure_frequency() -> u64 { /// On x86_64, this is slightly expensive, so it should be done once. pub fn frequency() -> TickFrequency { let frequency = measure_frequency(); - TickFrequency::Measured(frequency, MEASURE_FREQUENCY_DURATION) + TickFrequency::Measured(frequency) }