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