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, }
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 #[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 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 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", "rdtsc",
266 lateout("eax") eax,
267 lateout("edx") edx,
268 options(nostack) );
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 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 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, pub day: u8, 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 loop {
378 if leap_year(year) {
379 if days < 366 {
380 break;
381 }
382 days -= 366; } else if days < 365 {
384 break;
385 } else {
386 days -= 365; }
388 year += 1;
389 }
390
391 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}