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