xref: /DragonOS/kernel/src/time/timekeeping.rs (revision 6cf1947dcf7d114ca0503a2bc876412b18c21247)
1 use alloc::sync::Arc;
2 use core::sync::atomic::{compiler_fence, AtomicBool, AtomicI64, AtomicUsize, Ordering};
3 use log::{debug, info};
4 use system_error::SystemError;
5 
6 use crate::{
7     arch::{CurrentIrqArch, CurrentTimeArch},
8     exception::InterruptArch,
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             debug!("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         let prev = self.last_update_cpu_cycle.load(Ordering::SeqCst);
168         CurrentTimeArch::cycles2ns(CurrentTimeArch::get_cycles().wrapping_sub(prev))
169     }
170 
171     fn mark_update_wall_time_ok(&self) {
172         self.last_update_cpu_cycle
173             .store(CurrentTimeArch::get_cycles(), Ordering::SeqCst);
174     }
175 }
176 
177 #[inline(always)]
178 pub fn timekeeper() -> &'static Timekeeper {
179     let r = unsafe { __TIMEKEEPER.as_ref().unwrap() };
180 
181     return r;
182 }
183 
184 pub fn timekeeper_init() {
185     unsafe { __TIMEKEEPER = Some(Timekeeper::new()) };
186 }
187 
188 /// # 获取1970.1.1至今的UTC时间戳(最小单位:nsec)
189 ///
190 /// ## 返回值
191 ///
192 /// * 'TimeSpec' - 时间戳
193 pub fn getnstimeofday() -> PosixTimeSpec {
194     // debug!("enter getnstimeofday");
195 
196     let nsecs;
197     let mut xtime: PosixTimeSpec;
198     loop {
199         match timekeeper().inner.try_read_irqsave() {
200             None => continue,
201             Some(tk) => {
202                 xtime = tk.xtime;
203                 drop(tk);
204                 // 提供基于cpu周期数的ns时间,以便在两次update_wall_time之间提供更好的精度
205                 let cpu_delta_ns = timekeeper().do_read_cpu_cycle_ns() as u64;
206 
207                 // 尚未同步到xtime的时间
208                 let tmp_delta_ns = __ADDED_USEC.load(Ordering::SeqCst) as u64 * 1000;
209 
210                 nsecs = cpu_delta_ns + tmp_delta_ns;
211                 // TODO 不同架构可能需要加上不同的偏移量
212                 break;
213             }
214         }
215     }
216     xtime.tv_nsec += nsecs as i64;
217     xtime.tv_sec += xtime.tv_nsec / NSEC_PER_SEC as i64;
218     xtime.tv_nsec %= NSEC_PER_SEC as i64;
219     // debug!("getnstimeofday: xtime = {:?}, nsecs = {:}", xtime, nsecs);
220 
221     // TODO 将xtime和当前时间源的时间相加
222 
223     return xtime;
224 }
225 
226 /// # 获取1970.1.1至今的UTC时间戳(最小单位:usec)
227 ///
228 /// ## 返回值
229 ///
230 /// * 'PosixTimeval' - 时间戳
231 pub fn do_gettimeofday() -> PosixTimeval {
232     let tp = getnstimeofday();
233     return PosixTimeval {
234         tv_sec: tp.tv_sec,
235         tv_usec: (tp.tv_nsec / 1000) as i32,
236     };
237 }
238 
239 pub fn do_settimeofday64(time: PosixTimeSpec) -> Result<(), SystemError> {
240     timekeeper().inner.write_irqsave().xtime = time;
241     // todo: 模仿linux,实现时间误差校准。
242     // https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/time/timekeeping.c?fi=do_settimeofday64#1312
243     return Ok(());
244 }
245 
246 /// # 初始化timekeeping模块
247 #[inline(never)]
248 pub fn timekeeping_init() {
249     info!("Initializing timekeeping module...");
250     let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
251     timekeeper_init();
252 
253     // TODO 有ntp模块后 在此初始化ntp模块
254 
255     let clock = clocksource_default_clock();
256     clock
257         .enable()
258         .expect("clocksource_default_clock enable failed");
259     timekeeper().timekeeper_setup_internals(clock);
260     // 暂时不支持其他架构平台对时间的设置 所以使用x86平台对应值初始化
261     let mut timekeeper = timekeeper().inner.write_irqsave();
262     timekeeper.xtime.tv_nsec = ktime_get_real_ns();
263 
264     //参考https://elixir.bootlin.com/linux/v4.4/source/kernel/time/timekeeping.c#L1251 对wtm进行初始化
265     (
266         timekeeper.wall_to_monotonic.tv_nsec,
267         timekeeper.wall_to_monotonic.tv_sec,
268     ) = (-timekeeper.xtime.tv_nsec, -timekeeper.xtime.tv_sec);
269 
270     __ADDED_USEC.store(0, Ordering::SeqCst);
271 
272     drop(irq_guard);
273     drop(timekeeper);
274     jiffies_init();
275     info!("timekeeping_init successfully");
276 }
277 
278 /// # 使用当前时钟源增加wall time
279 pub fn update_wall_time(delta_us: i64) {
280     // debug!("enter update_wall_time, stack_use = {:}",stack_use);
281     compiler_fence(Ordering::SeqCst);
282     let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
283     // 如果在休眠那就不更新
284     if TIMEKEEPING_SUSPENDED.load(Ordering::SeqCst) {
285         return;
286     }
287 
288     // ===== 请不要删除这些注释 =====
289     // let clock = timekeeper.clock.clone().unwrap();
290     // let clock_data = clock.clocksource_data();
291     // let offset = (clock.read().div(clock_data.watchdog_last).data()) & clock_data.mask.bits();
292 
293     // timekeeper.xtime_nsec = (timekeeper.xtime.tv_nsec as u64) << timekeeper.shift;
294     // // TODO 当有ntp模块之后 需要将timekeep与ntp进行同步并检查
295     // timekeeper.xtime.tv_nsec = ((timekeeper.xtime_nsec as i64) >> timekeeper.shift) + 1;
296     // timekeeper.xtime_nsec -= (timekeeper.xtime.tv_nsec as u64) << timekeeper.shift;
297 
298     // timekeeper.xtime.tv_nsec += offset as i64;
299     // while unlikely(timekeeper.xtime.tv_nsec >= NSEC_PER_SEC.into()) {
300     //     timekeeper.xtime.tv_nsec -= NSEC_PER_SEC as i64;
301     //     timekeeper.xtime.tv_sec += 1;
302     //     // TODO 需要处理闰秒
303     // }
304     // ================
305     compiler_fence(Ordering::SeqCst);
306 
307     __ADDED_USEC.fetch_add(delta_us, Ordering::SeqCst);
308     compiler_fence(Ordering::SeqCst);
309     let mut retry = 10;
310 
311     let usec = __ADDED_USEC.load(Ordering::SeqCst);
312 
313     // 一分钟同步一次
314     loop {
315         if (usec & !((1 << 26) - 1)) != 0 {
316             if __ADDED_USEC
317                 .compare_exchange(usec, 0, Ordering::SeqCst, Ordering::SeqCst)
318                 .is_ok()
319                 || retry == 0
320             {
321                 // 同步时间
322                 // 我感觉这里会出问题:多个读者不退出的话,写者就无法写入
323                 // 然后这里会超时,导致在中断返回之后,会不断的进入这个中断,最终爆栈。
324                 let mut timekeeper = timekeeper().inner.write_irqsave();
325                 timekeeper.xtime.tv_nsec = ktime_get_real_ns();
326                 timekeeper.xtime.tv_sec = 0;
327                 __ADDED_USEC.store(0, Ordering::SeqCst);
328 
329                 drop(timekeeper);
330                 break;
331             }
332             retry -= 1;
333         } else {
334             break;
335         }
336     }
337     timekeeper().mark_update_wall_time_ok();
338     // TODO 需要检查是否更新时间源
339     compiler_fence(Ordering::SeqCst);
340     drop(irq_guard);
341     compiler_fence(Ordering::SeqCst);
342 }
343 // TODO timekeeping_adjust
344 // TODO wall_to_monotic
345