kernel/devices/clock/
mod.rs1mod 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 pub nanoseconds: u64,
32 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 fn name(&self) -> &'static str;
102 fn get_time(&self) -> ClockTime;
105 fn granularity(&self) -> u64;
108 fn require_calibration(&self) -> bool;
111 fn rating(&self) -> u64 {
114 1
116 }
117}
118
119struct SystemTime {
121 start_unix: ClockTime,
123 last_tick: ClockTime,
125 startup_offset: ClockTime,
127 device: Option<Arc<dyn ClockDevice>>,
129}
130
131impl SystemTime {
132 fn new(rtc: &Rtc) -> Self {
133 let time = rtc.get_time();
134 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 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 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 cpu::cpu().push_cli();
187
188 let mut rtc_time = rtc.get_time();
189 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: RwLock<Vec<Arc<dyn ClockDevice>>>,
235 rtc: Rtc,
237 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 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 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 CLOCKS
311 .set(Clock::new(Rtc::new(century_reg)))
312 .expect("Clock is already initialized");
313
314 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 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}