moto_sys/
time.rs

1use core::arch::asm;
2use core::sync::atomic::*;
3use core::time::Duration;
4
5use super::KernelStaticPage;
6
7#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
8pub struct Instant {
9    tsc_val: u64,
10}
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub struct SystemTime {
14    nanos: u64, // Note that SystemTime uses nanos vs Instant which uses tsc.
15}
16
17#[allow(unused)]
18pub const UNIX_EPOCH: SystemTime = SystemTime { nanos: 0u64 };
19pub const NANOS_IN_SEC: u64 = 1_000_000_000;
20
21impl Instant {
22    pub const fn nan() -> Self {
23        Instant { tsc_val: 0 }
24    }
25    pub fn is_nan(&self) -> bool {
26        self.tsc_val == 0
27    }
28
29    pub fn from_u64(val: u64) -> Self {
30        Instant { tsc_val: val }
31    }
32
33    pub fn as_u64(&self) -> u64 {
34        self.tsc_val
35    }
36
37    pub fn from_nanos(nanos: u64) -> Self {
38        Instant {
39            tsc_val: nanos_to_tsc(nanos),
40        }
41    }
42
43    pub fn now() -> Self {
44        Instant { tsc_val: rdtsc() }
45    }
46
47    pub fn raw_tsc(&self) -> u64 {
48        self.tsc_val
49    }
50
51    pub fn duration_since(&self, earlier: Instant) -> Duration {
52        if earlier.tsc_val > self.tsc_val {
53            // TODO: figure out why this happens in hyperv + qemu.
54            #[cfg(all(not(feature = "rustc-dep-of-std"), feature = "userspace"))]
55            super::syscalls::SysMem::log(
56                alloc::format!(
57                    "time goes back: earlier: {:x} > later: {:x}",
58                    earlier.tsc_val,
59                    self.tsc_val
60                )
61                .as_str(),
62            )
63            .ok();
64
65            #[cfg(feature = "rustc-dep-of-std")]
66            super::syscalls::SysMem::log("fros-sys: time: time goes back").ok();
67            return Duration::ZERO;
68        }
69
70        let tsc_diff = self.tsc_val - earlier.tsc_val;
71        if tsc_diff == 0 {
72            return Duration::ZERO;
73        }
74
75        let tsc_in_sec = KernelStaticPage::get().tsc_in_sec;
76        if core::intrinsics::unlikely(tsc_in_sec == 0) {
77            return Duration::ZERO;
78        }
79        let secs = tsc_diff / tsc_in_sec;
80        let nanos = tsc_to_nanos(tsc_diff % tsc_in_sec);
81
82        Duration::new(secs, nanos as u32)
83    }
84
85    pub fn elapsed(&self) -> Duration {
86        Instant::now().duration_since(self.clone())
87    }
88
89    pub const fn infinite_future() -> Self {
90        Instant { tsc_val: u64::MAX }
91    }
92
93    pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
94        if *self < *other {
95            return None;
96        }
97
98        let result_tsc = self.tsc_val - other.tsc_val;
99        let result_nanos = tsc_to_nanos_128(result_tsc);
100        if result_nanos > (u64::MAX as u128) {
101            None
102        } else {
103            Some(Duration::from_nanos(result_nanos as u64))
104        }
105    }
106
107    pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
108        let tsc_secs = other
109            .as_secs()
110            .checked_mul(KernelStaticPage::get().tsc_in_sec)?;
111        let tsc_diff = nanos_to_tsc(other.subsec_nanos() as u64).checked_add(tsc_secs)?;
112
113        Some(Instant {
114            tsc_val: self.tsc_val.checked_add(tsc_diff)?,
115        })
116    }
117
118    pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
119        let tsc_secs = other
120            .as_secs()
121            .checked_mul(KernelStaticPage::get().tsc_in_sec)?;
122        let tsc_diff = nanos_to_tsc(other.subsec_nanos() as u64).checked_add(tsc_secs)?;
123
124        if tsc_diff > self.tsc_val {
125            None
126        } else {
127            Some(Instant {
128                tsc_val: self.tsc_val - tsc_diff,
129            })
130        }
131    }
132}
133
134impl core::ops::Add<Duration> for Instant {
135    type Output = Instant;
136
137    fn add(self, other: Duration) -> Instant {
138        let tsc_secs = other.as_secs() * KernelStaticPage::get().tsc_in_sec;
139        let tsc_diff = nanos_to_tsc(other.subsec_nanos() as u64) + tsc_secs;
140
141        Instant {
142            tsc_val: self.tsc_val + tsc_diff,
143        }
144    }
145}
146
147impl core::ops::Sub<Duration> for Instant {
148    type Output = Instant;
149
150    fn sub(self, other: Duration) -> Self::Output {
151        let tsc_secs = other.as_secs() * KernelStaticPage::get().tsc_in_sec;
152        let tsc_diff = nanos_to_tsc(other.subsec_nanos() as u64) + tsc_secs;
153
154        Instant {
155            tsc_val: self.tsc_val - tsc_diff,
156        }
157    }
158}
159
160pub fn system_start_time() -> super::time::Instant {
161    Instant {
162        tsc_val: KernelStaticPage::get().system_start_time_tsc,
163    }
164}
165
166pub fn since_system_start() -> Duration {
167    Instant::now()
168        .checked_sub_instant(&Instant {
169            tsc_val: KernelStaticPage::get().system_start_time_tsc,
170        })
171        .unwrap()
172}
173
174#[allow(unused)]
175impl SystemTime {
176    pub fn now() -> Self {
177        SystemTime {
178            nanos: abs_nanos_from_tsc(rdtsc()),
179        }
180    }
181
182    pub fn from_u64(val: u64) -> Self {
183        Self { nanos: val }
184    }
185
186    pub fn as_u64(&self) -> u64 {
187        self.nanos
188    }
189
190    pub fn as_unix_ts(&self) -> u64 {
191        self.nanos
192    }
193
194    pub fn from_unix_ts(val: u64) -> Self {
195        Self { nanos: val }
196    }
197
198    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
199        if self.nanos >= other.nanos {
200            Ok(Duration::from_nanos(self.nanos - other.nanos))
201        } else {
202            Err(Duration::from_nanos(other.nanos - self.nanos))
203        }
204    }
205
206    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
207        let result_nanos = self.nanos as u128 + other.as_nanos();
208        if result_nanos > (u64::MAX as u128) {
209            None
210        } else {
211            Some(Self {
212                nanos: result_nanos as u64,
213            })
214        }
215    }
216
217    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
218        let other_nanos = other.as_nanos();
219        if self.nanos as u128 >= other_nanos {
220            Some(Self {
221                nanos: self.nanos - (other_nanos as u64),
222            })
223        } else {
224            None
225        }
226    }
227}
228
229fn abs_nanos_from_tsc(tsc_val: u64) -> u64 {
230    /*  see https://www.kernel.org/doc/Documentation/virt/kvm/msr.rst
231        time = (current_tsc - tsc_timestamp)
232        if (tsc_shift >= 0)
233            time <<= tsc_shift;
234        else
235            time >>= -tsc_shift;
236        time = (time * tsc_to_system_mul) >> 32
237        time = time + system_time
238    */
239    fence(Ordering::Acquire);
240    let page = KernelStaticPage::get();
241    let mut time = tsc_val - page.tsc_ts;
242    let tsc_shift = page.tsc_shift;
243    if tsc_shift >= 0 {
244        time <<= tsc_shift;
245    } else {
246        time >>= -tsc_shift;
247    }
248
249    // TODO: sometimes this overflows in debug mode.
250    let (mul, _overflow) = time.overflowing_mul(page.tsc_mul as u64);
251
252    time = mul >> 32;
253    time += page.system_time;
254
255    page.base_nsec + time
256}
257
258fn rdtsc() -> u64 {
259    let mut eax: u32;
260    let mut edx: u32;
261
262    unsafe {
263        asm!(
264            "lfence",  // Prevent the CPU from reordering.
265            "rdtsc",
266            lateout("eax") eax,
267            lateout("edx") edx,
268            options(nostack)  // Don't say "nomem", otherwise the compiler might reorder.
269        );
270    }
271    ((edx as u64) << 32) | (eax as u64)
272}
273
274fn tsc_to_nanos_128(tsc: u64) -> u128 {
275    fence(Ordering::Acquire);
276    let page = KernelStaticPage::get();
277
278    let mut nanos = tsc as u128;
279    let tsc_shift = page.tsc_shift;
280    if tsc_shift >= 0 {
281        nanos <<= tsc_shift;
282    } else {
283        nanos >>= -tsc_shift;
284    }
285
286    nanos * (page.tsc_mul as u128) >> 32
287}
288
289fn tsc_to_nanos(tsc: u64) -> u64 {
290    fence(Ordering::Acquire);
291    let page = KernelStaticPage::get();
292
293    let mut nanos = tsc;
294    let tsc_shift = page.tsc_shift;
295    if tsc_shift >= 0 {
296        nanos <<= tsc_shift;
297    } else {
298        nanos >>= -tsc_shift;
299    }
300
301    // TODO: this may overflow and panic. Fix.
302    let (mul, _overflow) = nanos.overflowing_mul(page.tsc_mul as u64);
303    mul >> 32
304}
305
306fn nanos_to_tsc(nanos: u64) -> u64 {
307    fence(Ordering::Acquire);
308    let page = KernelStaticPage::get();
309
310    let tsc_shift = page.tsc_shift;
311
312    // TODO: optimize?
313    // TODO: fix panic on overflow.
314    let mut res = if nanos >= (1u64 << 32) {
315        (nanos >> 4) * ((1u64 << 36) / (page.tsc_mul as u64))
316    } else {
317        (nanos << 32) / (page.tsc_mul as u64)
318    };
319
320    if tsc_shift >= 0 {
321        res >>= tsc_shift;
322    } else {
323        res <<= -tsc_shift;
324    }
325
326    return res;
327}
328
329#[derive(Debug)]
330pub struct UtcDateTime {
331    pub year: u32,
332    pub month: u8, // starts with 1
333    pub day: u8,   // starts with 1
334    pub hour: u8,
335    pub minute: u8,
336    pub second: u8,
337    pub nanosecond: u32,
338}
339
340impl core::fmt::Display for UtcDateTime {
341    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
342        write!(
343            f,
344            "{}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}Z",
345            self.year,
346            self.month,
347            self.day,
348            self.hour,
349            self.minute,
350            self.second,
351            self.nanosecond / (1000 * 1000)
352        )
353    }
354}
355
356impl UtcDateTime {
357    pub fn from_unix_nanos(nanos: u128) -> Self {
358        let st = nanos as u64;
359        let nanosecond = (st % (1000 * 1000 * 1000)) as u32;
360
361        let seconds = (st - (nanosecond as u64)) / (1000 * 1000 * 1000);
362        let time = seconds % (24 * 60 * 60);
363
364        let second = (time % 60) as u8;
365        let minutes = (time - (second as u64)) / 60;
366        let minute = (minutes % 60) as u8;
367        let hour = ((minutes - (minute as u64)) / 60) as u8;
368
369        let mut days = (seconds - time) / (24 * 60 * 60);
370        let mut year: u32 = 1970;
371
372        fn leap_year(year: u32) -> bool {
373            (year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0))
374        }
375
376        // Find the year.
377        loop {
378            if leap_year(year) {
379                if days < 366 {
380                    break;
381                }
382                days -= 366; // leap year
383            } else if days < 365 {
384                break;
385            } else {
386                days -= 365; // normal year
387            }
388            year += 1;
389        }
390
391        // Find the month and day.
392        const MONTHS: [u8; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
393        let mut month: u8 = 0;
394        loop {
395            if month == 1 {
396                if leap_year(year) {
397                    if days < 29 {
398                        break;
399                    }
400                    days -= 29;
401                    month += 1;
402                    continue;
403                } else if days < 28 {
404                    break;
405                }
406                days -= 28;
407                month += 1;
408                continue;
409            }
410            if days < MONTHS[month as usize] as u64 {
411                break;
412            }
413            days -= MONTHS[month as usize] as u64;
414            month += 1;
415        }
416
417        Self {
418            year,
419            month: month + 1,
420            day: (days + 1) as u8,
421            hour,
422            minute,
423            second,
424            nanosecond,
425        }
426    }
427}