xref: /DragonOS/kernel/src/time/timekeeping.rs (revision 6fc066ac11d2f9a3ac629d57487a6144fda1ac63)
136fd0130Shoumkh use alloc::sync::Arc;
2b8ed3825SDonkey Kane use core::sync::atomic::{compiler_fence, AtomicBool, AtomicI64, AtomicUsize, Ordering};
3da152319SLoGin use system_error::SystemError;
436fd0130Shoumkh 
536fd0130Shoumkh use crate::{
6b8ed3825SDonkey Kane     arch::{CurrentIrqArch, CurrentTimeArch},
736fd0130Shoumkh     exception::InterruptArch,
840fe15e0SLoGin     kdebug, kinfo,
9b8ed3825SDonkey Kane     libs::rwlock::{RwLock, RwLockReadGuard},
105b59005fSLoGin     time::{
115b59005fSLoGin         jiffies::{clocksource_default_clock, jiffies_init},
125b59005fSLoGin         timekeep::ktime_get_real_ns,
13*6fc066acSJomo         PosixTimeSpec,
145b59005fSLoGin     },
1536fd0130Shoumkh };
1636fd0130Shoumkh 
1736fd0130Shoumkh use super::{
1836fd0130Shoumkh     clocksource::{clocksource_cyc2ns, Clocksource, CycleNum, HZ},
1936fd0130Shoumkh     syscall::PosixTimeval,
20b8ed3825SDonkey Kane     TimeArch, NSEC_PER_SEC,
2136fd0130Shoumkh };
2236fd0130Shoumkh /// NTP周期频率
2336fd0130Shoumkh pub const NTP_INTERVAL_FREQ: u64 = HZ;
2436fd0130Shoumkh /// NTP周期长度
2536fd0130Shoumkh pub const NTP_INTERVAL_LENGTH: u64 = NSEC_PER_SEC as u64 / NTP_INTERVAL_FREQ;
2636fd0130Shoumkh /// NTP转换比例
2736fd0130Shoumkh pub const NTP_SCALE_SHIFT: u32 = 32;
2836fd0130Shoumkh 
2936fd0130Shoumkh /// timekeeping休眠标志,false为未休眠
3036fd0130Shoumkh pub static TIMEKEEPING_SUSPENDED: AtomicBool = AtomicBool::new(false);
3136fd0130Shoumkh /// 已经递增的微秒数
3236fd0130Shoumkh static __ADDED_USEC: AtomicI64 = AtomicI64::new(0);
3336fd0130Shoumkh /// timekeeper全局变量,用于管理timekeeper模块
3436fd0130Shoumkh static mut __TIMEKEEPER: Option<Timekeeper> = None;
3536fd0130Shoumkh 
3636fd0130Shoumkh #[derive(Debug)]
37b8ed3825SDonkey Kane pub struct Timekeeper {
38b8ed3825SDonkey Kane     inner: RwLock<TimekeeperData>,
39b8ed3825SDonkey Kane 
40b8ed3825SDonkey Kane     /// 上一次更新墙上时间时的CPU周期数
41b8ed3825SDonkey Kane     last_update_cpu_cycle: AtomicUsize,
42b8ed3825SDonkey Kane }
4336fd0130Shoumkh 
4436fd0130Shoumkh #[allow(dead_code)]
4536fd0130Shoumkh #[derive(Debug)]
4636fd0130Shoumkh pub struct TimekeeperData {
4736fd0130Shoumkh     /// 用于计时的当前时钟源。
4836fd0130Shoumkh     clock: Option<Arc<dyn Clocksource>>,
4936fd0130Shoumkh     /// 当前时钟源的移位值。
5036fd0130Shoumkh     shift: i32,
5136fd0130Shoumkh     /// 一个NTP间隔中的时钟周期数。
5236fd0130Shoumkh     cycle_interval: CycleNum,
5336fd0130Shoumkh     /// 一个NTP间隔中时钟移位的纳秒数。
5436fd0130Shoumkh     xtime_interval: u64,
5536fd0130Shoumkh     ///
5636fd0130Shoumkh     xtime_remainder: i64,
5736fd0130Shoumkh     /// 每个NTP间隔累积的原始纳米秒
5836fd0130Shoumkh     raw_interval: i64,
5936fd0130Shoumkh     /// 时钟移位纳米秒余数
6036fd0130Shoumkh     xtime_nsec: u64,
6136fd0130Shoumkh     /// 积累时间和ntp时间在ntp位移纳秒量上的差距
6236fd0130Shoumkh     ntp_error: i64,
6336fd0130Shoumkh     /// 用于转换时钟偏移纳秒和ntp偏移纳秒的偏移量
6436fd0130Shoumkh     ntp_error_shift: i32,
6536fd0130Shoumkh     /// NTP调整时钟乘法器
6636fd0130Shoumkh     mult: u32,
67*6fc066acSJomo     raw_time: PosixTimeSpec,
68*6fc066acSJomo     wall_to_monotonic: PosixTimeSpec,
69*6fc066acSJomo     total_sleep_time: PosixTimeSpec,
70*6fc066acSJomo     xtime: PosixTimeSpec,
7136fd0130Shoumkh }
7236fd0130Shoumkh impl TimekeeperData {
7336fd0130Shoumkh     pub fn new() -> Self {
7436fd0130Shoumkh         Self {
7536fd0130Shoumkh             clock: None,
7636fd0130Shoumkh             shift: Default::default(),
77b8ed3825SDonkey Kane             cycle_interval: CycleNum::new(0),
7836fd0130Shoumkh             xtime_interval: Default::default(),
7936fd0130Shoumkh             xtime_remainder: Default::default(),
8036fd0130Shoumkh             raw_interval: Default::default(),
8136fd0130Shoumkh             xtime_nsec: Default::default(),
8236fd0130Shoumkh             ntp_error: Default::default(),
8336fd0130Shoumkh             ntp_error_shift: Default::default(),
8436fd0130Shoumkh             mult: Default::default(),
85*6fc066acSJomo             xtime: PosixTimeSpec {
8636fd0130Shoumkh                 tv_nsec: 0,
8736fd0130Shoumkh                 tv_sec: 0,
8836fd0130Shoumkh             },
89*6fc066acSJomo             wall_to_monotonic: PosixTimeSpec {
9036fd0130Shoumkh                 tv_nsec: 0,
9136fd0130Shoumkh                 tv_sec: 0,
9236fd0130Shoumkh             },
93*6fc066acSJomo             total_sleep_time: PosixTimeSpec {
9436fd0130Shoumkh                 tv_nsec: 0,
9536fd0130Shoumkh                 tv_sec: 0,
9636fd0130Shoumkh             },
97*6fc066acSJomo             raw_time: PosixTimeSpec {
9836fd0130Shoumkh                 tv_nsec: 0,
9936fd0130Shoumkh                 tv_sec: 0,
10036fd0130Shoumkh             },
10136fd0130Shoumkh         }
10236fd0130Shoumkh     }
10336fd0130Shoumkh }
10436fd0130Shoumkh impl Timekeeper {
105b8ed3825SDonkey Kane     fn new() -> Self {
106b8ed3825SDonkey Kane         Self {
107b8ed3825SDonkey Kane             inner: RwLock::new(TimekeeperData::new()),
108b8ed3825SDonkey Kane             last_update_cpu_cycle: AtomicUsize::new(0),
109b8ed3825SDonkey Kane         }
110b8ed3825SDonkey Kane     }
111b8ed3825SDonkey Kane 
11236fd0130Shoumkh     /// # 设置timekeeper的参数
11336fd0130Shoumkh     ///
11436fd0130Shoumkh     /// ## 参数
11536fd0130Shoumkh     ///
11636fd0130Shoumkh     /// * 'clock' - 指定的时钟实际类型。初始为ClocksourceJiffies
11736fd0130Shoumkh     pub fn timekeeper_setup_internals(&self, clock: Arc<dyn Clocksource>) {
118b8ed3825SDonkey Kane         let mut timekeeper = self.inner.write_irqsave();
11936fd0130Shoumkh         // 更新clock
12036fd0130Shoumkh         let mut clock_data = clock.clocksource_data();
12136fd0130Shoumkh         clock_data.watchdog_last = clock.read();
12236fd0130Shoumkh         if clock.update_clocksource_data(clock_data).is_err() {
12336fd0130Shoumkh             kdebug!("timekeeper_setup_internals:update_clocksource_data run failed");
12436fd0130Shoumkh         }
12536fd0130Shoumkh         timekeeper.clock.replace(clock.clone());
12636fd0130Shoumkh 
12736fd0130Shoumkh         let clock_data = clock.clocksource_data();
12836fd0130Shoumkh         let mut temp = NTP_INTERVAL_LENGTH << clock_data.shift;
12936fd0130Shoumkh         let ntpinterval = temp;
13036fd0130Shoumkh         temp += (clock_data.mult / 2) as u64;
13136fd0130Shoumkh         // do div
13236fd0130Shoumkh 
133b8ed3825SDonkey Kane         timekeeper.cycle_interval = CycleNum::new(temp);
13436fd0130Shoumkh         timekeeper.xtime_interval = temp * clock_data.mult as u64;
13540fe15e0SLoGin         // 这里可能存在下界溢出问题,debug模式下会报错panic
13636fd0130Shoumkh         timekeeper.xtime_remainder = (ntpinterval - timekeeper.xtime_interval) as i64;
13736fd0130Shoumkh         timekeeper.raw_interval = (timekeeper.xtime_interval >> clock_data.shift) as i64;
13836fd0130Shoumkh         timekeeper.xtime_nsec = 0;
13936fd0130Shoumkh         timekeeper.shift = clock_data.shift as i32;
14036fd0130Shoumkh 
14136fd0130Shoumkh         timekeeper.ntp_error = 0;
14236fd0130Shoumkh         timekeeper.ntp_error_shift = (NTP_SCALE_SHIFT - clock_data.shift) as i32;
14336fd0130Shoumkh 
14436fd0130Shoumkh         timekeeper.mult = clock_data.mult;
14536fd0130Shoumkh     }
14636fd0130Shoumkh 
147b8ed3825SDonkey Kane     /// # 获取当前时钟源距离上次watchdog检测走过的纳秒数
14836fd0130Shoumkh     #[allow(dead_code)]
14936fd0130Shoumkh     pub fn tk_get_ns(&self) -> u64 {
150b8ed3825SDonkey Kane         let timekeeper: RwLockReadGuard<'_, TimekeeperData> = self.inner.read_irqsave();
15136fd0130Shoumkh         let clock = timekeeper.clock.clone().unwrap();
1520d6cf65aSLoGin         drop(timekeeper);
153b8ed3825SDonkey Kane 
15436fd0130Shoumkh         let clock_now = clock.read();
155911132c4SDonkey Kane         let clock_data = clock.clocksource_data();
156911132c4SDonkey Kane         let clock_delta = clock_now.div(clock_data.watchdog_last).data() & clock_data.mask.bits();
157b8ed3825SDonkey Kane 
158b8ed3825SDonkey Kane         return clocksource_cyc2ns(
159b8ed3825SDonkey Kane             CycleNum::new(clock_delta),
160b8ed3825SDonkey Kane             clock_data.mult,
161b8ed3825SDonkey Kane             clock_data.shift,
162b8ed3825SDonkey Kane         );
163b8ed3825SDonkey Kane     }
164b8ed3825SDonkey Kane 
165b8ed3825SDonkey Kane     #[inline]
166b8ed3825SDonkey Kane     fn do_read_cpu_cycle_ns(&self) -> usize {
167b8ed3825SDonkey Kane         CurrentTimeArch::cycles2ns(
168b8ed3825SDonkey Kane             CurrentTimeArch::get_cycles()
169b8ed3825SDonkey Kane                 .wrapping_sub(self.last_update_cpu_cycle.load(Ordering::SeqCst)),
170b8ed3825SDonkey Kane         )
171b8ed3825SDonkey Kane     }
172b8ed3825SDonkey Kane 
173b8ed3825SDonkey Kane     fn mark_update_wall_time_ok(&self) {
174b8ed3825SDonkey Kane         self.last_update_cpu_cycle
175b8ed3825SDonkey Kane             .store(CurrentTimeArch::get_cycles(), Ordering::SeqCst);
17636fd0130Shoumkh     }
17736fd0130Shoumkh }
178b8ed3825SDonkey Kane 
179b8ed3825SDonkey Kane #[inline(always)]
18036fd0130Shoumkh pub fn timekeeper() -> &'static Timekeeper {
1818d94ea66SYJwu2023     let r = unsafe { __TIMEKEEPER.as_ref().unwrap() };
1828d94ea66SYJwu2023 
1838d94ea66SYJwu2023     return r;
18436fd0130Shoumkh }
18536fd0130Shoumkh 
18636fd0130Shoumkh pub fn timekeeper_init() {
187b8ed3825SDonkey Kane     unsafe { __TIMEKEEPER = Some(Timekeeper::new()) };
18836fd0130Shoumkh }
18936fd0130Shoumkh 
19036fd0130Shoumkh /// # 获取1970.1.1至今的UTC时间戳(最小单位:nsec)
19136fd0130Shoumkh ///
19236fd0130Shoumkh /// ## 返回值
19336fd0130Shoumkh ///
19436fd0130Shoumkh /// * 'TimeSpec' - 时间戳
195*6fc066acSJomo pub fn getnstimeofday() -> PosixTimeSpec {
19640fe15e0SLoGin     // kdebug!("enter getnstimeofday");
19736fd0130Shoumkh 
198911132c4SDonkey Kane     let nsecs;
199*6fc066acSJomo     let mut xtime: PosixTimeSpec;
20036fd0130Shoumkh     loop {
201b8ed3825SDonkey Kane         match timekeeper().inner.try_read_irqsave() {
20236fd0130Shoumkh             None => continue,
20336fd0130Shoumkh             Some(tk) => {
204b8ed3825SDonkey Kane                 xtime = tk.xtime;
20536fd0130Shoumkh                 drop(tk);
206b8ed3825SDonkey Kane                 // 提供基于cpu周期数的ns时间,以便在两次update_wall_time之间提供更好的精度
207b8ed3825SDonkey Kane                 let cpu_delta_ns = timekeeper().do_read_cpu_cycle_ns() as u64;
208b8ed3825SDonkey Kane 
209b8ed3825SDonkey Kane                 // 尚未同步到xtime的时间
210b8ed3825SDonkey Kane                 let tmp_delta_ns = __ADDED_USEC.load(Ordering::SeqCst) as u64 * 1000;
211b8ed3825SDonkey Kane 
212b8ed3825SDonkey Kane                 nsecs = cpu_delta_ns + tmp_delta_ns;
21336fd0130Shoumkh                 // TODO 不同架构可能需要加上不同的偏移量
21436fd0130Shoumkh                 break;
21536fd0130Shoumkh             }
21636fd0130Shoumkh         }
21736fd0130Shoumkh     }
218b8ed3825SDonkey Kane     xtime.tv_nsec += nsecs as i64;
219b8ed3825SDonkey Kane     xtime.tv_sec += xtime.tv_nsec / NSEC_PER_SEC as i64;
220b8ed3825SDonkey Kane     xtime.tv_nsec %= NSEC_PER_SEC as i64;
221b8ed3825SDonkey Kane     // kdebug!("getnstimeofday: xtime = {:?}, nsecs = {:}", xtime, nsecs);
22236fd0130Shoumkh 
22336fd0130Shoumkh     // TODO 将xtime和当前时间源的时间相加
22436fd0130Shoumkh 
225b8ed3825SDonkey Kane     return xtime;
22636fd0130Shoumkh }
22736fd0130Shoumkh 
22836fd0130Shoumkh /// # 获取1970.1.1至今的UTC时间戳(最小单位:usec)
22936fd0130Shoumkh ///
23036fd0130Shoumkh /// ## 返回值
23136fd0130Shoumkh ///
23236fd0130Shoumkh /// * 'PosixTimeval' - 时间戳
23336fd0130Shoumkh pub fn do_gettimeofday() -> PosixTimeval {
23436fd0130Shoumkh     let tp = getnstimeofday();
23536fd0130Shoumkh     return PosixTimeval {
23636fd0130Shoumkh         tv_sec: tp.tv_sec,
23736fd0130Shoumkh         tv_usec: (tp.tv_nsec / 1000) as i32,
23836fd0130Shoumkh     };
23936fd0130Shoumkh }
24036fd0130Shoumkh 
241*6fc066acSJomo pub fn do_settimeofday64(time: PosixTimeSpec) -> Result<(), SystemError> {
242b8ed3825SDonkey Kane     timekeeper().inner.write_irqsave().xtime = time;
243da152319SLoGin     // todo: 模仿linux,实现时间误差校准。
244da152319SLoGin     // https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/time/timekeeping.c?fi=do_settimeofday64#1312
245da152319SLoGin     return Ok(());
246da152319SLoGin }
247da152319SLoGin 
24836fd0130Shoumkh /// # 初始化timekeeping模块
2495b59005fSLoGin #[inline(never)]
25036fd0130Shoumkh pub fn timekeeping_init() {
25140fe15e0SLoGin     kinfo!("Initializing timekeeping module...");
25236fd0130Shoumkh     let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
25336fd0130Shoumkh     timekeeper_init();
25436fd0130Shoumkh 
25536fd0130Shoumkh     // TODO 有ntp模块后 在此初始化ntp模块
25636fd0130Shoumkh 
25736fd0130Shoumkh     let clock = clocksource_default_clock();
25836fd0130Shoumkh     clock
25936fd0130Shoumkh         .enable()
26036fd0130Shoumkh         .expect("clocksource_default_clock enable failed");
26136fd0130Shoumkh     timekeeper().timekeeper_setup_internals(clock);
26236fd0130Shoumkh     // 暂时不支持其他架构平台对时间的设置 所以使用x86平台对应值初始化
263b8ed3825SDonkey Kane     let mut timekeeper = timekeeper().inner.write_irqsave();
26436fd0130Shoumkh     timekeeper.xtime.tv_nsec = ktime_get_real_ns();
26536fd0130Shoumkh 
266911132c4SDonkey Kane     //参考https://elixir.bootlin.com/linux/v4.4/source/kernel/time/timekeeping.c#L1251 对wtm进行初始化
267911132c4SDonkey Kane     (
268911132c4SDonkey Kane         timekeeper.wall_to_monotonic.tv_nsec,
269911132c4SDonkey Kane         timekeeper.wall_to_monotonic.tv_sec,
270911132c4SDonkey Kane     ) = (-timekeeper.xtime.tv_nsec, -timekeeper.xtime.tv_sec);
27136fd0130Shoumkh 
27236fd0130Shoumkh     __ADDED_USEC.store(0, Ordering::SeqCst);
27336fd0130Shoumkh 
27436fd0130Shoumkh     drop(irq_guard);
275b8ed3825SDonkey Kane     drop(timekeeper);
2765b59005fSLoGin     jiffies_init();
27740fe15e0SLoGin     kinfo!("timekeeping_init successfully");
27836fd0130Shoumkh }
27936fd0130Shoumkh 
28036fd0130Shoumkh /// # 使用当前时钟源增加wall time
2810d6cf65aSLoGin pub fn update_wall_time(delta_us: i64) {
28236fd0130Shoumkh     // kdebug!("enter update_wall_time, stack_use = {:}",stack_use);
28336fd0130Shoumkh     compiler_fence(Ordering::SeqCst);
28436fd0130Shoumkh     let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
28536fd0130Shoumkh     // 如果在休眠那就不更新
28636fd0130Shoumkh     if TIMEKEEPING_SUSPENDED.load(Ordering::SeqCst) {
28736fd0130Shoumkh         return;
28836fd0130Shoumkh     }
28936fd0130Shoumkh 
29036fd0130Shoumkh     // ===== 请不要删除这些注释 =====
29136fd0130Shoumkh     // let clock = timekeeper.clock.clone().unwrap();
29236fd0130Shoumkh     // let clock_data = clock.clocksource_data();
29336fd0130Shoumkh     // let offset = (clock.read().div(clock_data.watchdog_last).data()) & clock_data.mask.bits();
29436fd0130Shoumkh 
29536fd0130Shoumkh     // timekeeper.xtime_nsec = (timekeeper.xtime.tv_nsec as u64) << timekeeper.shift;
29636fd0130Shoumkh     // // TODO 当有ntp模块之后 需要将timekeep与ntp进行同步并检查
29736fd0130Shoumkh     // timekeeper.xtime.tv_nsec = ((timekeeper.xtime_nsec as i64) >> timekeeper.shift) + 1;
29836fd0130Shoumkh     // timekeeper.xtime_nsec -= (timekeeper.xtime.tv_nsec as u64) << timekeeper.shift;
29936fd0130Shoumkh 
30036fd0130Shoumkh     // timekeeper.xtime.tv_nsec += offset as i64;
30136fd0130Shoumkh     // while unlikely(timekeeper.xtime.tv_nsec >= NSEC_PER_SEC.into()) {
30236fd0130Shoumkh     //     timekeeper.xtime.tv_nsec -= NSEC_PER_SEC as i64;
30336fd0130Shoumkh     //     timekeeper.xtime.tv_sec += 1;
30436fd0130Shoumkh     //     // TODO 需要处理闰秒
30536fd0130Shoumkh     // }
30636fd0130Shoumkh     // ================
30736fd0130Shoumkh     compiler_fence(Ordering::SeqCst);
308be8cdf4bSLoGin 
3090d6cf65aSLoGin     __ADDED_USEC.fetch_add(delta_us, Ordering::SeqCst);
31036fd0130Shoumkh     compiler_fence(Ordering::SeqCst);
31136fd0130Shoumkh     let mut retry = 10;
31236fd0130Shoumkh 
31336fd0130Shoumkh     let usec = __ADDED_USEC.load(Ordering::SeqCst);
31436fd0130Shoumkh 
315be8cdf4bSLoGin     // 一分钟同步一次
31636fd0130Shoumkh     loop {
31736fd0130Shoumkh         if (usec & !((1 << 26) - 1)) != 0 {
31836fd0130Shoumkh             if __ADDED_USEC
31936fd0130Shoumkh                 .compare_exchange(usec, 0, Ordering::SeqCst, Ordering::SeqCst)
32036fd0130Shoumkh                 .is_ok()
32136fd0130Shoumkh                 || retry == 0
32236fd0130Shoumkh             {
32336fd0130Shoumkh                 // 同步时间
32436fd0130Shoumkh                 // 我感觉这里会出问题:多个读者不退出的话,写者就无法写入
32536fd0130Shoumkh                 // 然后这里会超时,导致在中断返回之后,会不断的进入这个中断,最终爆栈。
326b8ed3825SDonkey Kane                 let mut timekeeper = timekeeper().inner.write_irqsave();
32736fd0130Shoumkh                 timekeeper.xtime.tv_nsec = ktime_get_real_ns();
32836fd0130Shoumkh                 timekeeper.xtime.tv_sec = 0;
329b8ed3825SDonkey Kane                 __ADDED_USEC.store(0, Ordering::SeqCst);
330b8ed3825SDonkey Kane 
33136fd0130Shoumkh                 drop(timekeeper);
33236fd0130Shoumkh                 break;
33336fd0130Shoumkh             }
33436fd0130Shoumkh             retry -= 1;
33536fd0130Shoumkh         } else {
33636fd0130Shoumkh             break;
33736fd0130Shoumkh         }
33836fd0130Shoumkh     }
339b8ed3825SDonkey Kane     timekeeper().mark_update_wall_time_ok();
34036fd0130Shoumkh     // TODO 需要检查是否更新时间源
34136fd0130Shoumkh     compiler_fence(Ordering::SeqCst);
34236fd0130Shoumkh     drop(irq_guard);
34336fd0130Shoumkh     compiler_fence(Ordering::SeqCst);
34436fd0130Shoumkh }
34536fd0130Shoumkh // TODO timekeeping_adjust
34636fd0130Shoumkh // TODO wall_to_monotic
347