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