fix(platform/timer): on x86_64, elide usage of asm!() and use _rdtsc() intrinsic

This commit is contained in:
2025-11-03 02:57:22 -05:00
parent be63c5171b
commit ba634ed68a
3 changed files with 8 additions and 55 deletions

View File

@@ -17,7 +17,7 @@ pub enum TickFrequency {
/// The platform provides the tick frequency. /// The platform provides the tick frequency.
Hardware(u64), Hardware(u64),
/// The tick frequency is measured internally. /// The tick frequency is measured internally.
Measured(u64, Duration), Measured(u64),
} }
impl TickFrequency { impl TickFrequency {
@@ -25,7 +25,7 @@ impl TickFrequency {
fn ticks(&self) -> u64 { fn ticks(&self) -> u64 {
match self { match self {
TickFrequency::Hardware(frequency) => *frequency, TickFrequency::Hardware(frequency) => *frequency,
TickFrequency::Measured(frequency, _) => *frequency, TickFrequency::Measured(frequency) => *frequency,
} }
} }

View File

@@ -10,16 +10,6 @@ pub fn ticks() -> u64 {
counter 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. /// Our frequency is provided by cntfrq_el0 on the platform.
pub fn frequency() -> TickFrequency { pub fn frequency() -> TickFrequency {
let frequency: u64; let frequency: u64;

View File

@@ -1,5 +1,4 @@
use crate::platform::timer::TickFrequency; use crate::platform::timer::TickFrequency;
use core::arch::asm;
use core::time::Duration; use core::time::Duration;
/// We will measure the frequency of the timer based on 1000 microseconds. /// 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. /// Read the number of ticks from the platform timer.
pub fn ticks() -> u64 { pub fn ticks() -> u64 {
let mut eax: u32; // SAFETY: Reads the platform timer, which is safe in any context.
let mut edx: u32; unsafe { core::arch::x86_64::_rdtsc() }
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
} }
/// Measure the frequency of the platform timer. /// Measure the frequency of the platform timer.
/// NOTE: Intentionally, we do not synchronize rdtsc during measurement to match systemd behavior.
fn measure_frequency() -> u64 { fn measure_frequency() -> u64 {
let start = start(); let start = ticks();
uefi::boot::stall(MEASURE_FREQUENCY_DURATION); uefi::boot::stall(MEASURE_FREQUENCY_DURATION);
let stop = stop(); let stop = ticks();
let elapsed = stop.wrapping_sub(start) as f64; let elapsed = stop.wrapping_sub(start) as f64;
(elapsed / MEASURE_FREQUENCY_DURATION.as_secs_f64()) as u64 (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. /// On x86_64, this is slightly expensive, so it should be done once.
pub fn frequency() -> TickFrequency { pub fn frequency() -> TickFrequency {
let frequency = measure_frequency(); let frequency = measure_frequency();
TickFrequency::Measured(frequency, MEASURE_FREQUENCY_DURATION) TickFrequency::Measured(frequency)
} }