kernel/devices/clock/
mod.rs

1mod hardware_timer;
2mod rtc;
3mod tsc;
4
5use core::fmt;
6
7use alloc::{sync::Arc, vec::Vec};
8use tracing::info;
9
10use crate::{
11    acpi::tables::{self, BiosTables, Facp},
12    cpu,
13    sync::{once::OnceLock, spin::rwlock::RwLock},
14};
15
16use self::rtc::Rtc;
17
18pub const NANOS_PER_SEC: u64 = 1_000_000_000;
19pub const FEMTOS_PER_SEC: u64 = 1_000_000_000_000_000;
20pub const NANOS_PER_FEMTO: u64 = 1_000_000;
21
22static CLOCKS: OnceLock<Clock> = OnceLock::new();
23
24pub fn clocks() -> &'static Clock {
25    CLOCKS.get()
26}
27
28#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
29pub struct ClockTime {
30    /// nanoseconds added to `seconds`
31    pub nanoseconds: u64,
32    /// seconds passed since a fixed point in time
33    pub seconds: u64,
34}
35
36#[allow(dead_code)]
37impl ClockTime {
38    pub fn as_nanos(&self) -> u64 {
39        self.seconds * NANOS_PER_SEC + self.nanoseconds
40    }
41}
42
43impl Ord for ClockTime {
44    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
45        self.seconds
46            .cmp(&other.seconds)
47            .then(self.nanoseconds.cmp(&other.nanoseconds))
48    }
49}
50
51impl PartialOrd for ClockTime {
52    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
53        Some(self.cmp(other))
54    }
55}
56
57impl core::ops::Sub for ClockTime {
58    type Output = Self;
59
60    fn sub(self, rhs: Self) -> Self::Output {
61        let nanoseconds = if self.nanoseconds < rhs.nanoseconds {
62            self.nanoseconds + 1_000_000_000 - rhs.nanoseconds
63        } else {
64            self.nanoseconds - rhs.nanoseconds
65        };
66        let seconds = self.seconds
67            - rhs.seconds
68            - if self.nanoseconds < rhs.nanoseconds {
69                1
70            } else {
71                0
72            };
73        Self {
74            nanoseconds,
75            seconds,
76        }
77    }
78}
79
80impl core::ops::Add for ClockTime {
81    type Output = Self;
82
83    fn add(self, rhs: Self) -> Self::Output {
84        let nanoseconds = self.nanoseconds + rhs.nanoseconds;
85        let seconds = self.seconds + rhs.seconds + nanoseconds / 1_000_000_000;
86        Self {
87            nanoseconds: nanoseconds % 1_000_000_000,
88            seconds,
89        }
90    }
91}
92
93impl core::ops::AddAssign for ClockTime {
94    fn add_assign(&mut self, rhs: Self) {
95        *self = *self + rhs;
96    }
97}
98
99trait ClockDevice: Send + Sync {
100    /// Returns the name of the device
101    fn name(&self) -> &'static str;
102    /// Returns the current time of the device with no relation to anything
103    /// The system will use consecutive calls to determine the time
104    fn get_time(&self) -> ClockTime;
105    /// Returns the granularity of the device in nanoseconds, i.e. the smallest time unit it can measure
106    /// Must be at least 1
107    fn granularity(&self) -> u64;
108    /// Returns true if the device needs to be calibration
109    /// i.e. it doesn't count time correctly
110    fn require_calibration(&self) -> bool;
111    /// Returns the rating of the device, i.e. how good it is
112    /// The higher the better
113    fn rating(&self) -> u64 {
114        // default rating is 1
115        1
116    }
117}
118
119/// Accurate always increasing time source
120struct SystemTime {
121    /// The time when the system was started
122    start_unix: ClockTime,
123    /// The last time we ticked the system time
124    last_tick: ClockTime,
125    /// The system time since the start
126    startup_offset: ClockTime,
127    /// device used to get the time
128    device: Option<Arc<dyn ClockDevice>>,
129}
130
131impl SystemTime {
132    fn new(rtc: &Rtc) -> Self {
133        let time = rtc.get_time();
134        // let device_time = device.get_time();
135
136        let timestamp = time.seconds_since_unix_epoch().expect("Must be after 1970");
137        info!("Time now: {time} - UTC");
138        info!("System start timestamp: {}", timestamp);
139
140        let start_unix = ClockTime {
141            nanoseconds: 0,
142            seconds: timestamp,
143        };
144
145        Self {
146            start_unix,
147            last_tick: ClockTime {
148                nanoseconds: 0,
149                seconds: 0,
150            },
151            startup_offset: ClockTime {
152                nanoseconds: 0,
153                seconds: 0,
154            },
155            device: None,
156        }
157    }
158
159    fn tick(&mut self) {
160        if let Some(device) = &self.device {
161            let time = device.get_time();
162            let diff = time - self.last_tick;
163            self.startup_offset += diff;
164            self.last_tick = time;
165        }
166    }
167
168    /// Will update the device if this one is different
169    fn update_device(&mut self, device: Arc<dyn ClockDevice>, rtc: &Rtc) {
170        if let Some(current_device) = &self.device {
171            if Arc::ptr_eq(&device, current_device) {
172                return;
173            }
174
175            // switch the counters to use the new device
176            let time = current_device.get_time();
177            let new_time = device.get_time();
178            let diff = time - self.last_tick;
179            self.startup_offset += diff;
180
181            self.device = Some(device);
182            self.last_tick = new_time
183        } else {
184            // this is the first time, make sure we are aligned with rtc
185
186            cpu::cpu().push_cli();
187
188            let mut rtc_time = rtc.get_time();
189            // wait for the next second to start
190            loop {
191                let new_rtc_time = rtc.get_time();
192                if new_rtc_time.seconds != rtc_time.seconds {
193                    rtc_time = new_rtc_time;
194                    break;
195                }
196            }
197            let device_time = device.get_time();
198
199            let timestamp = rtc_time
200                .seconds_since_unix_epoch()
201                .expect("Must be after 1970");
202            info!("Adjusted Time now: {rtc_time} - UTC");
203            info!("Adjusted System start timestamp: {}", timestamp);
204
205            self.last_tick = device_time;
206            self.device = Some(device);
207            self.startup_offset = ClockTime {
208                nanoseconds: 0,
209                seconds: 0,
210            };
211            self.start_unix = ClockTime {
212                nanoseconds: 0,
213                seconds: rtc_time
214                    .seconds_since_unix_epoch()
215                    .expect("Must be after 1970"),
216            };
217
218            cpu::cpu().pop_cli();
219        }
220    }
221
222    fn time_since_startup(&self) -> ClockTime {
223        self.startup_offset
224    }
225
226    fn time_since_unix_epoch(&self) -> ClockTime {
227        self.start_unix + self.startup_offset
228    }
229}
230
231#[allow(dead_code)]
232pub struct Clock {
233    /// devices sorted based on their rating
234    devices: RwLock<Vec<Arc<dyn ClockDevice>>>,
235    /// Used to determine the outside world time and use it as a base
236    rtc: Rtc,
237    /// System time
238    system_time: RwLock<SystemTime>,
239}
240
241impl fmt::Debug for Clock {
242    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243        f.debug_struct("Clock").finish()
244    }
245}
246
247impl Clock {
248    fn new(rtc: Rtc) -> Self {
249        Self {
250            devices: RwLock::new(Vec::new()),
251            system_time: RwLock::new(SystemTime::new(&rtc)),
252            rtc,
253        }
254    }
255
256    fn add_device(&self, device: Arc<dyn ClockDevice>) {
257        info!(
258            "Adding clock device: {}, rating: {}",
259            device.name(),
260            device.rating()
261        );
262        let mut devs = self.devices.write();
263        devs.push(device);
264        devs.sort_unstable_by_key(|device| -(device.rating() as i64));
265        self.system_time
266            .write()
267            .update_device(devs[0].clone(), &self.rtc);
268    }
269
270    #[allow(dead_code)]
271    fn get_best_clock(&self) -> Option<Arc<dyn ClockDevice>> {
272        self.devices.read().first().map(Arc::clone)
273    }
274
275    fn get_best_for_calibration(&self) -> Option<Arc<dyn ClockDevice>> {
276        self.devices
277            .read()
278            .iter()
279            .find(|device| !device.require_calibration())
280            .map(Arc::clone)
281    }
282
283    #[allow(dead_code)]
284    pub fn tick_system_time(&self) {
285        self.system_time.write().tick();
286    }
287
288    #[allow(dead_code)]
289    pub fn time_since_startup(&self) -> ClockTime {
290        // TODO: find a better way to do this
291        let mut time = self.system_time.write();
292        time.tick();
293        time.time_since_startup()
294    }
295
296    #[allow(dead_code)]
297    pub fn time_since_unix_epoch(&self) -> ClockTime {
298        // TODO: find a better way to do this
299        let mut time = self.system_time.write();
300        time.tick();
301        time.time_since_unix_epoch()
302    }
303}
304
305pub fn init(bios_tables: &BiosTables) {
306    let facp = bios_tables.rsdt.get_table::<Facp>();
307    let century_reg = facp.map(|facp| facp.century);
308
309    // create the clock
310    CLOCKS
311        .set(Clock::new(Rtc::new(century_reg)))
312        .expect("Clock is already initialized");
313
314    // init HPET
315    let hpet_table = bios_tables.rsdt.get_table::<tables::Hpet>();
316
317    let hardware_timer = hardware_timer::HardwareTimer::init(hpet_table);
318    clocks().add_device(hardware_timer);
319
320    // init TSC
321    if let Some(tsc) = tsc::Tsc::new(
322        clocks()
323            .get_best_for_calibration()
324            .expect("Have a clock that can be used as a base for TSC calibration")
325            .as_ref(),
326    ) {
327        clocks().add_device(Arc::new(tsc));
328    }
329}