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