xref: /DragonOS/kernel/src/time/timekeeping.rs (revision 1ea2daad8121b77ed704e6d7c3a09f478147441d)
1 use alloc::sync::Arc;
2 use core::intrinsics::{likely, unlikely};
3 use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
4 use log::{debug, info, warn};
5 use system_error::SystemError;
6 
7 use crate::{
8     arch::CurrentIrqArch,
9     exception::InterruptArch,
10     libs::rwlock::RwLock,
11     time::{
12         jiffies::{clocksource_default_clock, jiffies_init},
13         timekeep::ktime_get_real_ns,
14         PosixTimeSpec,
15     },
16 };
17 
18 use super::timekeep::{ktime_t, timespec_to_ktime};
19 use super::{
20     clocksource::{clocksource_cyc2ns, Clocksource, CycleNum, HZ},
21     syscall::PosixTimeval,
22     NSEC_PER_SEC,
23 };
24 /// NTP周期频率
25 pub const NTP_INTERVAL_FREQ: u64 = HZ;
26 /// NTP周期长度
27 pub const NTP_INTERVAL_LENGTH: u64 = NSEC_PER_SEC as u64 / NTP_INTERVAL_FREQ;
28 /// NTP转换比例
29 pub const NTP_SCALE_SHIFT: u32 = 32;
30 
31 /// timekeeping休眠标志,false为未休眠
32 pub static TIMEKEEPING_SUSPENDED: AtomicBool = AtomicBool::new(false);
33 /// timekeeper全局变量,用于管理timekeeper模块
34 static mut __TIMEKEEPER: Option<Timekeeper> = None;
35 
36 #[derive(Debug)]
37 pub struct Timekeeper {
38     inner: RwLock<TimekeeperData>,
39 }
40 
41 #[allow(dead_code)]
42 #[derive(Debug)]
43 pub struct TimekeeperData {
44     /// 用于计时的当前时钟源。
45     clock: Option<Arc<dyn Clocksource>>,
46     /// 当前时钟源的移位值。
47     shift: i32,
48     /// 一个NTP间隔中的时钟周期数。
49     cycle_interval: CycleNum,
50     /// 一个NTP间隔中时钟移位的纳秒数。
51     xtime_interval: u64,
52     ///
53     xtime_remainder: i64,
54     /// 每个NTP间隔累积的原始纳米秒
55     raw_interval: i64,
56     /// 时钟移位纳米秒余数
57     xtime_nsec: u64,
58     /// 积累时间和ntp时间在ntp位移纳秒量上的差距
59     ntp_error: i64,
60     /// 用于转换时钟偏移纳秒和ntp偏移纳秒的偏移量
61     ntp_error_shift: i32,
62     /// NTP调整时钟乘法器
63     mult: u32,
64     raw_time: PosixTimeSpec,
65     wall_to_monotonic: PosixTimeSpec,
66     total_sleep_time: PosixTimeSpec,
67     xtime: PosixTimeSpec,
68     /// 单调时间和实时时间的偏移量
69     real_time_offset: ktime_t,
70 }
71 impl TimekeeperData {
72     pub fn new() -> Self {
73         Self {
74             clock: None,
75             shift: Default::default(),
76             cycle_interval: CycleNum::new(0),
77             xtime_interval: Default::default(),
78             xtime_remainder: Default::default(),
79             raw_interval: Default::default(),
80             xtime_nsec: Default::default(),
81             ntp_error: Default::default(),
82             ntp_error_shift: Default::default(),
83             mult: Default::default(),
84             xtime: PosixTimeSpec {
85                 tv_nsec: 0,
86                 tv_sec: 0,
87             },
88             wall_to_monotonic: PosixTimeSpec {
89                 tv_nsec: 0,
90                 tv_sec: 0,
91             },
92             total_sleep_time: PosixTimeSpec {
93                 tv_nsec: 0,
94                 tv_sec: 0,
95             },
96             raw_time: PosixTimeSpec {
97                 tv_nsec: 0,
98                 tv_sec: 0,
99             },
100             real_time_offset: 0,
101         }
102     }
103 }
104 impl Timekeeper {
105     fn new() -> Self {
106         Self {
107             inner: RwLock::new(TimekeeperData::new()),
108         }
109     }
110 
111     /// # 设置timekeeper的参数
112     ///
113     /// ## 参数
114     ///
115     /// * 'clock' - 指定的时钟实际类型。初始为ClocksourceJiffies
116     pub fn timekeeper_setup_internals(&self, clock: Arc<dyn Clocksource>) {
117         let mut timekeeper = self.inner.write_irqsave();
118         // 更新clock
119         let mut clock_data = clock.clocksource_data();
120         clock_data.cycle_last = clock.read();
121         if clock.update_clocksource_data(clock_data).is_err() {
122             debug!("timekeeper_setup_internals:update_clocksource_data run failed");
123         }
124         timekeeper.clock.replace(clock.clone());
125 
126         let clock_data = clock.clocksource_data();
127         let mut temp = NTP_INTERVAL_LENGTH << clock_data.shift;
128         let ntpinterval = temp;
129         temp += (clock_data.mult / 2) as u64;
130         // do div
131 
132         timekeeper.cycle_interval = CycleNum::new(temp);
133         timekeeper.xtime_interval = temp * clock_data.mult as u64;
134         // 这里可能存在下界溢出问题,debug模式下会报错panic
135         timekeeper.xtime_remainder = (ntpinterval - timekeeper.xtime_interval) as i64;
136         timekeeper.raw_interval = (timekeeper.xtime_interval >> clock_data.shift) as i64;
137         timekeeper.xtime_nsec = 0;
138         timekeeper.shift = clock_data.shift as i32;
139 
140         timekeeper.ntp_error = 0;
141         timekeeper.ntp_error_shift = (NTP_SCALE_SHIFT - clock_data.shift) as i32;
142 
143         timekeeper.mult = clock_data.mult;
144     }
145 
146     pub fn timekeeping_get_ns(&self) -> i64 {
147         let timekeeper = self.inner.read_irqsave();
148         let clock = timekeeper.clock.clone().unwrap();
149 
150         let cycle_now = clock.read();
151         let clock_data = clock.clocksource_data();
152         let cycle_delta = (cycle_now.div(clock_data.cycle_last)).data() & clock_data.mask.bits();
153 
154         return clocksource_cyc2ns(
155             CycleNum::new(cycle_delta),
156             timekeeper.mult,
157             timekeeper.shift as u32,
158         ) as i64;
159     }
160 
161     /// # 处理大幅度调整
162     pub fn timekeeping_bigadjust(&self, error: i64, interval: i64, offset: i64) -> (i64, i64, i32) {
163         let mut error = error;
164         let mut interval = interval;
165         let mut offset = offset;
166 
167         // TODO: 计算look_head并调整ntp误差
168 
169         let tmp = interval;
170         let mut mult = 1;
171         let mut adj = 0;
172         if error < 0 {
173             error = -error;
174             interval = -interval;
175             offset = -offset;
176             mult = -1;
177         }
178         while error > tmp {
179             adj += 1;
180             error >>= 1;
181         }
182 
183         interval <<= adj;
184         offset <<= adj;
185         mult <<= adj;
186 
187         return (interval, offset, mult);
188     }
189 
190     /// # 调整时钟的mult减少ntp_error
191     pub fn timekeeping_adjust(&self, offset: i64) -> i64 {
192         let mut timekeeper = self.inner.write_irqsave();
193         let mut interval = timekeeper.cycle_interval.data() as i64;
194         let mut offset = offset;
195         let adj: i32;
196 
197         // 计算误差
198         let mut error = timekeeper.ntp_error >> (timekeeper.ntp_error_shift - 1);
199 
200         // 误差超过一个interval,就要进行调整
201         if error >= 0 {
202             if error > interval {
203                 error >>= 2;
204                 if likely(error <= interval) {
205                     adj = 1;
206                 } else {
207                     (interval, offset, adj) = self.timekeeping_bigadjust(error, interval, offset);
208                 }
209             } else {
210                 // 不需要校准
211                 return offset;
212             }
213         } else if -error > interval {
214             if likely(-error <= interval) {
215                 adj = -1;
216                 interval = -interval;
217                 offset = -offset;
218             } else {
219                 (interval, offset, adj) = self.timekeeping_bigadjust(error, interval, offset);
220             }
221         } else {
222             // 不需要校准
223             return offset;
224         }
225 
226         // 检查最大调整值,确保调整值不会超过时钟源允许的最大值
227         let clock_data = timekeeper.clock.clone().unwrap().clocksource_data();
228         if unlikely(
229             clock_data.maxadj != 0
230                 && (timekeeper.mult as i32 + adj
231                     > clock_data.mult as i32 + clock_data.maxadj as i32),
232         ) {
233             warn!(
234                 "Adjusting {:?} more than ({} vs {})",
235                 clock_data.name,
236                 timekeeper.mult as i32 + adj,
237                 clock_data.mult as i32 + clock_data.maxadj as i32
238             );
239         }
240 
241         if error > 0 {
242             timekeeper.mult += adj as u32;
243             timekeeper.xtime_interval += interval as u64;
244             timekeeper.xtime_nsec -= offset as u64;
245         } else {
246             timekeeper.mult -= adj as u32;
247             timekeeper.xtime_interval -= interval as u64;
248             timekeeper.xtime_nsec += offset as u64;
249         }
250         timekeeper.ntp_error -= (interval - offset) << timekeeper.ntp_error_shift;
251 
252         return offset;
253     }
254     /// # 用于累积时间间隔,并将其转换为纳秒时间
255     pub fn logarithmic_accumulation(&self, offset: u64, shift: i32) -> u64 {
256         let mut timekeeper = self.inner.write_irqsave();
257         let clock = timekeeper.clock.clone().unwrap();
258         let clock_data = clock.clocksource_data();
259         let nsecps = (NSEC_PER_SEC as u64) << timekeeper.shift;
260         let mut offset = offset;
261 
262         // 检查offset是否小于一个NTP周期间隔
263         if offset < timekeeper.cycle_interval.data() << shift {
264             return offset;
265         }
266 
267         // 累积一个移位的interval
268         offset -= timekeeper.cycle_interval.data() << shift;
269         clock_data
270             .cycle_last
271             .add(CycleNum::new(timekeeper.cycle_interval.data() << shift));
272         if clock.update_clocksource_data(clock_data).is_err() {
273             debug!("logarithmic_accumulation:update_clocksource_data run failed");
274         }
275         timekeeper.clock.replace(clock.clone());
276 
277         // 更新xime_nsec
278         timekeeper.xtime_nsec += timekeeper.xtime_interval << shift;
279         while timekeeper.xtime_nsec >= nsecps {
280             timekeeper.xtime_nsec -= nsecps;
281             timekeeper.xtime.tv_sec += 1;
282             // TODO: 处理闰秒
283         }
284 
285         // TODO:更新raw_time
286 
287         // TODO:计算ntp_error
288 
289         return offset;
290     }
291 }
292 
293 #[inline(always)]
294 pub fn timekeeper() -> &'static Timekeeper {
295     let r = unsafe { __TIMEKEEPER.as_ref().unwrap() };
296 
297     return r;
298 }
299 
300 pub fn timekeeper_init() {
301     unsafe { __TIMEKEEPER = Some(Timekeeper::new()) };
302 }
303 
304 /// # 获取1970.1.1至今的UTC时间戳(最小单位:nsec)
305 ///
306 /// ## 返回值
307 ///
308 /// * 'TimeSpec' - 时间戳
309 pub fn getnstimeofday() -> PosixTimeSpec {
310     // debug!("enter getnstimeofday");
311 
312     let nsecs;
313     let mut xtime: PosixTimeSpec;
314     loop {
315         match timekeeper().inner.try_read_irqsave() {
316             None => continue,
317             Some(tk) => {
318                 xtime = tk.xtime;
319                 drop(tk);
320 
321                 nsecs = timekeeper().timekeeping_get_ns();
322 
323                 // TODO 不同架构可能需要加上不同的偏移量
324                 break;
325             }
326         }
327     }
328     xtime.tv_nsec += nsecs;
329     xtime.tv_sec += xtime.tv_nsec / NSEC_PER_SEC as i64;
330     xtime.tv_nsec %= NSEC_PER_SEC as i64;
331     // debug!("getnstimeofday: xtime = {:?}, nsecs = {:}", xtime, nsecs);
332 
333     // TODO 将xtime和当前时间源的时间相加
334 
335     return xtime;
336 }
337 
338 /// # 获取1970.1.1至今的UTC时间戳(最小单位:usec)
339 ///
340 /// ## 返回值
341 ///
342 /// * 'PosixTimeval' - 时间戳
343 pub fn do_gettimeofday() -> PosixTimeval {
344     let tp = getnstimeofday();
345     return PosixTimeval {
346         tv_sec: tp.tv_sec,
347         tv_usec: (tp.tv_nsec / 1000) as i32,
348     };
349 }
350 
351 pub fn do_settimeofday64(time: PosixTimeSpec) -> Result<(), SystemError> {
352     timekeeper().inner.write_irqsave().xtime = time;
353     // todo: 模仿linux,实现时间误差校准。
354     // https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/time/timekeeping.c?fi=do_settimeofday64#1312
355     return Ok(());
356 }
357 
358 /// # 初始化timekeeping模块
359 #[inline(never)]
360 pub fn timekeeping_init() {
361     info!("Initializing timekeeping module...");
362     let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
363     timekeeper_init();
364 
365     // TODO 有ntp模块后 在此初始化ntp模块
366 
367     let clock = clocksource_default_clock();
368     clock
369         .enable()
370         .expect("clocksource_default_clock enable failed");
371     timekeeper().timekeeper_setup_internals(clock);
372     // 暂时不支持其他架构平台对时间的设置 所以使用x86平台对应值初始化
373     let mut timekeeper = timekeeper().inner.write_irqsave();
374     timekeeper.xtime.tv_nsec = ktime_get_real_ns();
375 
376     //参考https://elixir.bootlin.com/linux/v4.4/source/kernel/time/timekeeping.c#L1251 对wtm进行初始化
377     (
378         timekeeper.wall_to_monotonic.tv_nsec,
379         timekeeper.wall_to_monotonic.tv_sec,
380     ) = (-timekeeper.xtime.tv_nsec, -timekeeper.xtime.tv_sec);
381 
382     drop(irq_guard);
383     drop(timekeeper);
384     jiffies_init();
385     info!("timekeeping_init successfully");
386 }
387 
388 /// # 使用当前时钟源增加wall time
389 /// 参考:https://code.dragonos.org.cn/xref/linux-3.4.99/kernel/time/timekeeping.c#1041
390 pub fn update_wall_time() {
391     // debug!("enter update_wall_time, stack_use = {:}",stack_use);
392     compiler_fence(Ordering::SeqCst);
393     let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
394     // 如果在休眠那就不更新
395     if TIMEKEEPING_SUSPENDED.load(Ordering::SeqCst) {
396         return;
397     }
398 
399     let mut tk = timekeeper().inner.write_irqsave();
400     // 获取当前时钟源
401     let clock = tk.clock.clone().unwrap();
402     let clock_data = clock.clocksource_data();
403     // 计算从上一次更新周期以来经过的时钟周期数
404     let mut offset = (clock.read().div(clock_data.cycle_last).data()) & clock_data.mask.bits();
405     // 检查offset是否达到了一个NTP周期间隔
406     if offset < tk.cycle_interval.data() {
407         return;
408     }
409 
410     // 将纳秒部分转换为更高精度的格式
411     tk.xtime_nsec = (tk.xtime.tv_nsec as u64) << tk.shift;
412 
413     let mut shift = (offset.ilog2() - tk.cycle_interval.data().ilog2()) as i32;
414     shift = shift.max(0);
415     // let max_shift = (64 - (ntp_tick_length().ilog2()+1)) - 1;
416     // shift = min(shift, max_shift)
417     while offset >= tk.cycle_interval.data() {
418         offset = timekeeper().logarithmic_accumulation(offset, shift);
419         if offset < tk.cycle_interval.data() << shift {
420             shift -= 1;
421         }
422     }
423 
424     timekeeper().timekeeping_adjust(offset as i64);
425 
426     // 处理xtime_nsec下溢问题,并对NTP误差进行调整
427     if unlikely((tk.xtime_nsec as i64) < 0) {
428         let neg = -(tk.xtime_nsec as i64);
429         tk.xtime_nsec = 0;
430         tk.ntp_error += neg << tk.ntp_error_shift;
431     }
432 
433     // 将纳秒部分舍入后存储在xtime.tv_nsec中
434     tk.xtime.tv_nsec = ((tk.xtime_nsec as i64) >> tk.shift) + 1;
435     tk.xtime_nsec -= (tk.xtime.tv_nsec as u64) << tk.shift;
436 
437     // 确保经过舍入后的xtime.tv_nsec不会大于NSEC_PER_SEC,并在超过1秒的情况下进行适当的调整
438     if unlikely(tk.xtime.tv_nsec >= NSEC_PER_SEC.into()) {
439         tk.xtime.tv_nsec -= NSEC_PER_SEC as i64;
440         tk.xtime.tv_sec += 1;
441         // TODO: 处理闰秒
442     }
443 
444     // 更新时间的相关信息
445     timekeeping_update();
446 
447     compiler_fence(Ordering::SeqCst);
448     drop(irq_guard);
449     compiler_fence(Ordering::SeqCst);
450 }
451 // TODO wall_to_monotic
452 
453 /// 参考:https://code.dragonos.org.cn/xref/linux-3.4.99/kernel/time/timekeeping.c#190
454 pub fn timekeeping_update() {
455     // TODO:如果clearntp为true,则会清除NTP错误并调用ntp_clear()
456 
457     // 更新实时时钟偏移量,用于跟踪硬件时钟与系统时间的差异,以便进行时间校正
458     update_rt_offset();
459 }
460 
461 /// # 更新实时偏移量(墙上之间与单调时间的差值)
462 pub fn update_rt_offset() {
463     let mut timekeeper = timekeeper().inner.write_irqsave();
464     let ts = PosixTimeSpec::new(
465         -timekeeper.wall_to_monotonic.tv_sec,
466         -timekeeper.wall_to_monotonic.tv_nsec,
467     );
468     timekeeper.real_time_offset = timespec_to_ktime(ts);
469 }
470