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