axhal/platform/x86_pc/
time.rs1use raw_cpuid::CpuId;
2
3#[cfg(feature = "irq")]
4use int_ratio::Ratio;
5
6#[cfg(feature = "irq")]
7const LAPIC_TICKS_PER_SEC: u64 = 1_000_000_000; #[cfg(feature = "irq")]
10static mut NANOS_TO_LAPIC_TICKS_RATIO: Ratio = Ratio::zero();
11
12static mut INIT_TICK: u64 = 0;
13static mut CPU_FREQ_MHZ: u64 = axconfig::devices::TIMER_FREQUENCY as u64 / 1_000_000;
14
15static mut RTC_EPOCHOFFSET_NANOS: u64 = 0;
17
18pub fn current_ticks() -> u64 {
20 unsafe { core::arch::x86_64::_rdtsc() - INIT_TICK }
21}
22
23pub fn ticks_to_nanos(ticks: u64) -> u64 {
25 ticks * 1_000 / unsafe { CPU_FREQ_MHZ }
26}
27
28pub fn nanos_to_ticks(nanos: u64) -> u64 {
30 nanos * unsafe { CPU_FREQ_MHZ } / 1_000
31}
32
33pub fn epochoffset_nanos() -> u64 {
35 unsafe { RTC_EPOCHOFFSET_NANOS }
36}
37
38#[cfg(feature = "irq")]
42pub fn set_oneshot_timer(deadline_ns: u64) {
43 let lapic = super::apic::local_apic();
44 let now_ns = crate::time::monotonic_time_nanos();
45 unsafe {
46 if now_ns < deadline_ns {
47 let apic_ticks = NANOS_TO_LAPIC_TICKS_RATIO.mul_trunc(deadline_ns - now_ns);
48 assert!(apic_ticks <= u32::MAX as u64);
49 lapic.set_timer_initial(apic_ticks.max(1) as u32);
50 } else {
51 lapic.set_timer_initial(1);
52 }
53 }
54}
55
56pub(super) fn init_early() {
57 if let Some(freq) = CpuId::new()
58 .get_processor_frequency_info()
59 .map(|info| info.processor_base_frequency())
60 && freq > 0
61 {
62 axlog::ax_println!("Got TSC frequency by CPUID: {} MHz", freq);
63 unsafe { CPU_FREQ_MHZ = freq as u64 }
64 }
65
66 unsafe {
67 INIT_TICK = core::arch::x86_64::_rdtsc();
68 }
69
70 #[cfg(feature = "rtc")]
71 {
72 use x86_rtc::Rtc;
73
74 let eopch_time_nanos = Rtc::new().get_unix_timestamp() * 1_000_000_000;
77 unsafe {
78 RTC_EPOCHOFFSET_NANOS = eopch_time_nanos - ticks_to_nanos(INIT_TICK);
79 }
80 }
81}
82
83pub(super) fn init_primary() {
84 #[cfg(feature = "irq")]
85 unsafe {
86 use x2apic::lapic::{TimerDivide, TimerMode};
87 let lapic = super::apic::local_apic();
88 lapic.set_timer_mode(TimerMode::OneShot);
89 lapic.set_timer_divide(TimerDivide::Div256); lapic.enable_timer();
91
92 NANOS_TO_LAPIC_TICKS_RATIO = Ratio::new(
94 LAPIC_TICKS_PER_SEC as u32,
95 crate::time::NANOS_PER_SEC as u32,
96 );
97 }
98}
99
100#[cfg(feature = "smp")]
101pub(super) fn init_secondary() {
102 #[cfg(feature = "irq")]
103 unsafe {
104 super::apic::local_apic().enable_timer();
105 }
106}