xref: /DragonOS/kernel/src/time/timekeeping.rs (revision 2709e017d0d216d61b2caed3c7286459de7794c7)
1 use alloc::sync::Arc;
2 use core::sync::atomic::{compiler_fence, AtomicBool, AtomicI64, AtomicUsize, Ordering};
3 use system_error::SystemError;
4 
5 use crate::{
6     arch::{CurrentIrqArch, CurrentTimeArch},
7     exception::InterruptArch,
8     kdebug, kinfo,
9     libs::rwlock::{RwLock, RwLockReadGuard},
10     time::{
11         jiffies::{clocksource_default_clock, jiffies_init},
12         timekeep::ktime_get_real_ns,
13         PosixTimeSpec,
14     },
15 };
16 
17 use super::{
18     clocksource::{clocksource_cyc2ns, Clocksource, CycleNum, HZ},
19     syscall::PosixTimeval,
20     TimeArch, NSEC_PER_SEC,
21 };
22 /// NTP周期频率
23 pub const NTP_INTERVAL_FREQ: u64 = HZ;
24 /// NTP周期长度
25 pub const NTP_INTERVAL_LENGTH: u64 = NSEC_PER_SEC as u64 / NTP_INTERVAL_FREQ;
26 /// NTP转换比例
27 pub const NTP_SCALE_SHIFT: u32 = 32;
28 
29 /// timekeeping休眠标志,false为未休眠
30 pub static TIMEKEEPING_SUSPENDED: AtomicBool = AtomicBool::new(false);
31 /// 已经递增的微秒数
32 static __ADDED_USEC: AtomicI64 = AtomicI64::new(0);
33 /// timekeeper全局变量,用于管理timekeeper模块
34 static mut __TIMEKEEPER: Option<Timekeeper> = None;
35 
36 #[derive(Debug)]
37 pub struct Timekeeper {
38     inner: RwLock<TimekeeperData>,
39 
40     /// 上一次更新墙上时间时的CPU周期数
41     last_update_cpu_cycle: AtomicUsize,
42 }
43 
44 #[allow(dead_code)]
45 #[derive(Debug)]
46 pub struct TimekeeperData {
47     /// 用于计时的当前时钟源。
48     clock: Option<Arc<dyn Clocksource>>,
49     /// 当前时钟源的移位值。
50     shift: i32,
51     /// 一个NTP间隔中的时钟周期数。
52     cycle_interval: CycleNum,
53     /// 一个NTP间隔中时钟移位的纳秒数。
54     xtime_interval: u64,
55     ///
56     xtime_remainder: i64,
57     /// 每个NTP间隔累积的原始纳米秒
58     raw_interval: i64,
59     /// 时钟移位纳米秒余数
60     xtime_nsec: u64,
61     /// 积累时间和ntp时间在ntp位移纳秒量上的差距
62     ntp_error: i64,
63     /// 用于转换时钟偏移纳秒和ntp偏移纳秒的偏移量
64     ntp_error_shift: i32,
65     /// NTP调整时钟乘法器
66     mult: u32,
67     raw_time: PosixTimeSpec,
68     wall_to_monotonic: PosixTimeSpec,
69     total_sleep_time: PosixTimeSpec,
70     xtime: PosixTimeSpec,
71 }
72 impl TimekeeperData {
73     pub fn new() -> Self {
74         Self {
75             clock: None,
76             shift: Default::default(),
77             cycle_interval: CycleNum::new(0),
78             xtime_interval: Default::default(),
79             xtime_remainder: Default::default(),
80             raw_interval: Default::default(),
81             xtime_nsec: Default::default(),
82             ntp_error: Default::default(),
83             ntp_error_shift: Default::default(),
84             mult: Default::default(),
85             xtime: PosixTimeSpec {
86                 tv_nsec: 0,
87                 tv_sec: 0,
88             },
89             wall_to_monotonic: PosixTimeSpec {
90                 tv_nsec: 0,
91                 tv_sec: 0,
92             },
93             total_sleep_time: PosixTimeSpec {
94                 tv_nsec: 0,
95                 tv_sec: 0,
96             },
97             raw_time: PosixTimeSpec {
98                 tv_nsec: 0,
99                 tv_sec: 0,
100             },
101         }
102     }
103 }
104 impl Timekeeper {
105     fn new() -> Self {
106         Self {
107             inner: RwLock::new(TimekeeperData::new()),
108             last_update_cpu_cycle: AtomicUsize::new(0),
109         }
110     }
111 
112     /// # 设置timekeeper的参数
113     ///
114     /// ## 参数
115     ///
116     /// * 'clock' - 指定的时钟实际类型。初始为ClocksourceJiffies
117     pub fn timekeeper_setup_internals(&self, clock: Arc<dyn Clocksource>) {
118         let mut timekeeper = self.inner.write_irqsave();
119         // 更新clock
120         let mut clock_data = clock.clocksource_data();
121         clock_data.watchdog_last = clock.read();
122         if clock.update_clocksource_data(clock_data).is_err() {
123             kdebug!("timekeeper_setup_internals:update_clocksource_data run failed");
124         }
125         timekeeper.clock.replace(clock.clone());
126 
127         let clock_data = clock.clocksource_data();
128         let mut temp = NTP_INTERVAL_LENGTH << clock_data.shift;
129         let ntpinterval = temp;
130         temp += (clock_data.mult / 2) as u64;
131         // do div
132 
133         timekeeper.cycle_interval = CycleNum::new(temp);
134         timekeeper.xtime_interval = temp * clock_data.mult as u64;
135         // 这里可能存在下界溢出问题,debug模式下会报错panic
136         timekeeper.xtime_remainder = (ntpinterval - timekeeper.xtime_interval) as i64;
137         timekeeper.raw_interval = (timekeeper.xtime_interval >> clock_data.shift) as i64;
138         timekeeper.xtime_nsec = 0;
139         timekeeper.shift = clock_data.shift as i32;
140 
141         timekeeper.ntp_error = 0;
142         timekeeper.ntp_error_shift = (NTP_SCALE_SHIFT - clock_data.shift) as i32;
143 
144         timekeeper.mult = clock_data.mult;
145     }
146 
147     /// # 获取当前时钟源距离上次watchdog检测走过的纳秒数
148     #[allow(dead_code)]
149     pub fn tk_get_ns(&self) -> u64 {
150         let timekeeper: RwLockReadGuard<'_, TimekeeperData> = self.inner.read_irqsave();
151         let clock = timekeeper.clock.clone().unwrap();
152         drop(timekeeper);
153 
154         let clock_now = clock.read();
155         let clock_data = clock.clocksource_data();
156         let clock_delta = clock_now.div(clock_data.watchdog_last).data() & clock_data.mask.bits();
157 
158         return clocksource_cyc2ns(
159             CycleNum::new(clock_delta),
160             clock_data.mult,
161             clock_data.shift,
162         );
163     }
164 
165     #[inline]
166     fn do_read_cpu_cycle_ns(&self) -> usize {
167         CurrentTimeArch::cycles2ns(
168             CurrentTimeArch::get_cycles()
169                 .wrapping_sub(self.last_update_cpu_cycle.load(Ordering::SeqCst)),
170         )
171     }
172 
173     fn mark_update_wall_time_ok(&self) {
174         self.last_update_cpu_cycle
175             .store(CurrentTimeArch::get_cycles(), Ordering::SeqCst);
176     }
177 }
178 
179 #[inline(always)]
180 pub fn timekeeper() -> &'static Timekeeper {
181     let r = unsafe { __TIMEKEEPER.as_ref().unwrap() };
182 
183     return r;
184 }
185 
186 pub fn timekeeper_init() {
187     unsafe { __TIMEKEEPER = Some(Timekeeper::new()) };
188 }
189 
190 /// # 获取1970.1.1至今的UTC时间戳(最小单位:nsec)
191 ///
192 /// ## 返回值
193 ///
194 /// * 'TimeSpec' - 时间戳
195 pub fn getnstimeofday() -> PosixTimeSpec {
196     // kdebug!("enter getnstimeofday");
197 
198     let nsecs;
199     let mut xtime: PosixTimeSpec;
200     loop {
201         match timekeeper().inner.try_read_irqsave() {
202             None => continue,
203             Some(tk) => {
204                 xtime = tk.xtime;
205                 drop(tk);
206                 // 提供基于cpu周期数的ns时间,以便在两次update_wall_time之间提供更好的精度
207                 let cpu_delta_ns = timekeeper().do_read_cpu_cycle_ns() as u64;
208 
209                 // 尚未同步到xtime的时间
210                 let tmp_delta_ns = __ADDED_USEC.load(Ordering::SeqCst) as u64 * 1000;
211 
212                 nsecs = cpu_delta_ns + tmp_delta_ns;
213                 // TODO 不同架构可能需要加上不同的偏移量
214                 break;
215             }
216         }
217     }
218     xtime.tv_nsec += nsecs as i64;
219     xtime.tv_sec += xtime.tv_nsec / NSEC_PER_SEC as i64;
220     xtime.tv_nsec %= NSEC_PER_SEC as i64;
221     // kdebug!("getnstimeofday: xtime = {:?}, nsecs = {:}", xtime, nsecs);
222 
223     // TODO 将xtime和当前时间源的时间相加
224 
225     return xtime;
226 }
227 
228 /// # 获取1970.1.1至今的UTC时间戳(最小单位:usec)
229 ///
230 /// ## 返回值
231 ///
232 /// * 'PosixTimeval' - 时间戳
233 pub fn do_gettimeofday() -> PosixTimeval {
234     let tp = getnstimeofday();
235     return PosixTimeval {
236         tv_sec: tp.tv_sec,
237         tv_usec: (tp.tv_nsec / 1000) as i32,
238     };
239 }
240 
241 pub fn do_settimeofday64(time: PosixTimeSpec) -> Result<(), SystemError> {
242     timekeeper().inner.write_irqsave().xtime = time;
243     // todo: 模仿linux,实现时间误差校准。
244     // https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/time/timekeeping.c?fi=do_settimeofday64#1312
245     return Ok(());
246 }
247 
248 /// # 初始化timekeeping模块
249 #[inline(never)]
250 pub fn timekeeping_init() {
251     kinfo!("Initializing timekeeping module...");
252     let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
253     timekeeper_init();
254 
255     // TODO 有ntp模块后 在此初始化ntp模块
256 
257     let clock = clocksource_default_clock();
258     clock
259         .enable()
260         .expect("clocksource_default_clock enable failed");
261     timekeeper().timekeeper_setup_internals(clock);
262     // 暂时不支持其他架构平台对时间的设置 所以使用x86平台对应值初始化
263     let mut timekeeper = timekeeper().inner.write_irqsave();
264     timekeeper.xtime.tv_nsec = ktime_get_real_ns();
265 
266     //参考https://elixir.bootlin.com/linux/v4.4/source/kernel/time/timekeeping.c#L1251 对wtm进行初始化
267     (
268         timekeeper.wall_to_monotonic.tv_nsec,
269         timekeeper.wall_to_monotonic.tv_sec,
270     ) = (-timekeeper.xtime.tv_nsec, -timekeeper.xtime.tv_sec);
271 
272     __ADDED_USEC.store(0, Ordering::SeqCst);
273 
274     drop(irq_guard);
275     drop(timekeeper);
276     jiffies_init();
277     kinfo!("timekeeping_init successfully");
278 }
279 
280 /// # 使用当前时钟源增加wall time
281 pub fn update_wall_time(delta_us: i64) {
282     // kdebug!("enter update_wall_time, stack_use = {:}",stack_use);
283     compiler_fence(Ordering::SeqCst);
284     let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
285     // 如果在休眠那就不更新
286     if TIMEKEEPING_SUSPENDED.load(Ordering::SeqCst) {
287         return;
288     }
289 
290     // ===== 请不要删除这些注释 =====
291     // let clock = timekeeper.clock.clone().unwrap();
292     // let clock_data = clock.clocksource_data();
293     // let offset = (clock.read().div(clock_data.watchdog_last).data()) & clock_data.mask.bits();
294 
295     // timekeeper.xtime_nsec = (timekeeper.xtime.tv_nsec as u64) << timekeeper.shift;
296     // // TODO 当有ntp模块之后 需要将timekeep与ntp进行同步并检查
297     // timekeeper.xtime.tv_nsec = ((timekeeper.xtime_nsec as i64) >> timekeeper.shift) + 1;
298     // timekeeper.xtime_nsec -= (timekeeper.xtime.tv_nsec as u64) << timekeeper.shift;
299 
300     // timekeeper.xtime.tv_nsec += offset as i64;
301     // while unlikely(timekeeper.xtime.tv_nsec >= NSEC_PER_SEC.into()) {
302     //     timekeeper.xtime.tv_nsec -= NSEC_PER_SEC as i64;
303     //     timekeeper.xtime.tv_sec += 1;
304     //     // TODO 需要处理闰秒
305     // }
306     // ================
307     compiler_fence(Ordering::SeqCst);
308 
309     __ADDED_USEC.fetch_add(delta_us, Ordering::SeqCst);
310     compiler_fence(Ordering::SeqCst);
311     let mut retry = 10;
312 
313     let usec = __ADDED_USEC.load(Ordering::SeqCst);
314 
315     // 一分钟同步一次
316     loop {
317         if (usec & !((1 << 26) - 1)) != 0 {
318             if __ADDED_USEC
319                 .compare_exchange(usec, 0, Ordering::SeqCst, Ordering::SeqCst)
320                 .is_ok()
321                 || retry == 0
322             {
323                 // 同步时间
324                 // 我感觉这里会出问题:多个读者不退出的话,写者就无法写入
325                 // 然后这里会超时,导致在中断返回之后,会不断的进入这个中断,最终爆栈。
326                 let mut timekeeper = timekeeper().inner.write_irqsave();
327                 timekeeper.xtime.tv_nsec = ktime_get_real_ns();
328                 timekeeper.xtime.tv_sec = 0;
329                 __ADDED_USEC.store(0, Ordering::SeqCst);
330 
331                 drop(timekeeper);
332                 break;
333             }
334             retry -= 1;
335         } else {
336             break;
337         }
338     }
339     timekeeper().mark_update_wall_time_ok();
340     // TODO 需要检查是否更新时间源
341     compiler_fence(Ordering::SeqCst);
342     drop(irq_guard);
343     compiler_fence(Ordering::SeqCst);
344 }
345 // TODO timekeeping_adjust
346 // TODO wall_to_monotic
347